diff --git a/src/core/hle/D3D8/Direct3D9/CxbxPixelShaderTemplate.hlsl b/src/core/hle/D3D8/Direct3D9/CxbxPixelShaderTemplate.hlsl index a0c7db56a..b69b93393 100644 --- a/src/core/hle/D3D8/Direct3D9/CxbxPixelShaderTemplate.hlsl +++ b/src/core/hle/D3D8/Direct3D9/CxbxPixelShaderTemplate.hlsl @@ -53,6 +53,7 @@ uniform const float4 FC0 : register(c16); // Note : Maps to PSH_XBOX_CONSTANT_FC uniform const float4 FC1 : register(c17); // Note : Maps to PSH_XBOX_CONSTANT_FC1, must be generated as argument to xfc instead of C1 uniform const float4 BEM[4] : register(c19); // Note : PSH_XBOX_CONSTANT_BEM for 4 texture stages uniform const float4 LUM[4] : register(c23); // Note : PSH_XBOX_CONSTANT_LUM for 4 texture stages +uniform const float FRONTFACE_FACTOR : register(c27); // Note : PSH_XBOX_CONSTANT_LUM for 4 texture stages #define CM_LT(c) if(c < 0) clip(-1); // = PS_COMPAREMODE_[RSTQ]_LT @@ -335,11 +336,14 @@ PS_OUTPUT main(const PS_INPUT xIn) float3 s; // Actual texture coordinate sampling coordinates (temporary) float4 v; // Texture value (temporary) + // Determine if this is a front face or backface + bool isFrontFace = (xIn.iFF * FRONTFACE_FACTOR) >= 0; + // Initialize variables r0 = r1 = black; // Note : r0.a/r1.a will be overwritten by t0.a/t1.a (opaque_black will be retained for PS_TEXTUREMODES_NONE) // Note : VFACE/FrontFace has been unreliable, investigate again if some test-case shows bland colors - v0 = xIn.iFF > 0 ? xIn.iD0 : xIn.iB0; // Diffuse front/back - v1 = xIn.iFF > 0 ? xIn.iD1 : xIn.iB1; // Specular front/back + v0 = isFrontFace ? xIn.iD0 : xIn.iB0; // Diffuse front/back + v1 = isFrontFace ? xIn.iD1 : xIn.iB1; // Specular front/back fog = float4(c_fog.rgb, xIn.iFog); // color from PSH_XBOX_CONSTANT_FOG, alpha from vertex shader output / pixel shader input // Xbox shader program diff --git a/src/core/hle/D3D8/XbConvert.cpp b/src/core/hle/D3D8/XbConvert.cpp index 36899b2d7..1ea57bd1b 100644 --- a/src/core/hle/D3D8/XbConvert.cpp +++ b/src/core/hle/D3D8/XbConvert.cpp @@ -1504,8 +1504,8 @@ const RenderStateInfo DxbxRenderStateInfo[1+xbox::X_D3DRS_DONOTCULLUNCOMPRESSED] { "D3DRS_VERTEXBLEND" /*= 137*/, 3424, xtD3DVERTEXBLENDFLAGS, NV2A_SKIN_MODE, D3DRS_VERTEXBLEND }, { "D3DRS_FOGCOLOR" /*= 138*/, 3424, xtD3DCOLOR, NV2A_FOG_COLOR, D3DRS_FOGCOLOR }, // SwapRgb { "D3DRS_FILLMODE" /*= 139*/, 3424, xtD3DFILLMODE, NV2A_POLYGON_MODE_FRONT, D3DRS_FILLMODE }, - { "D3DRS_BACKFILLMODE" /*= 140*/, 3424, xtD3DFILLMODE, 0 }, // nsp. - { "D3DRS_TWOSIDEDLIGHTING" /*= 141*/, 3424, xtBOOL, NV2A_POLYGON_MODE_BACK }, // nsp. + { "D3DRS_BACKFILLMODE" /*= 140*/, 3424, xtD3DFILLMODE, NV2A_POLYGON_MODE_BACK }, // nsp. + { "D3DRS_TWOSIDEDLIGHTING" /*= 141*/, 3424, xtBOOL, 0 }, // nsp. // FIXME map from NV2A_LIGHT_MODEL { "D3DRS_NORMALIZENORMALS" /*= 142*/, 3424, xtBOOL, NV2A_NORMALIZE_ENABLE, D3DRS_NORMALIZENORMALS }, { "D3DRS_ZENABLE" /*= 143*/, 3424, xtBOOL, NV2A_DEPTH_TEST_ENABLE, D3DRS_ZENABLE }, // D3DZBUFFERTYPE? { "D3DRS_STENCILENABLE" /*= 144*/, 3424, xtBOOL, NV2A_STENCIL_ENABLE, D3DRS_STENCILENABLE }, diff --git a/src/core/hle/D3D8/XbPixelShader.cpp b/src/core/hle/D3D8/XbPixelShader.cpp index f092c9996..e9e68a1e6 100644 --- a/src/core/hle/D3D8/XbPixelShader.cpp +++ b/src/core/hle/D3D8/XbPixelShader.cpp @@ -630,8 +630,10 @@ constexpr int PSH_XBOX_CONSTANT_FOG = PSH_XBOX_CONSTANT_FC1 + 1; // = 18 constexpr int PSH_XBOX_CONSTANT_BEM = PSH_XBOX_CONSTANT_FOG + 1; // = 19..22 // Bump map Luminance registers constexpr int PSH_XBOX_CONSTANT_LUM = PSH_XBOX_CONSTANT_BEM + 4; // = 23..26 +// Which winding order to consider as the front face +constexpr int PSH_XBOX_CONSTANT_FRONTFACE_FACTOR = PSH_XBOX_CONSTANT_LUM + 4; // = 27 // This concludes the set of constants that need to be set on host : -constexpr int PSH_XBOX_CONSTANT_MAX = PSH_XBOX_CONSTANT_LUM + 4; // = 27 +constexpr int PSH_XBOX_CONSTANT_MAX = PSH_XBOX_CONSTANT_FRONTFACE_FACTOR + 1; // = 28 void DxbxUpdateActivePixelShader() // NOPATCH { @@ -768,6 +770,21 @@ void DxbxUpdateActivePixelShader() // NOPATCH } #endif + // Control whether to use front or back diffuse/specular colours + // This factor should be multipled with VFACE + // Test cases: + // Amped (snowboard trails should use front colours, but use both CW and CCW winding) + // TwoSidedLighting sample + float frontfaceFactor = 0; // 0 == always use the front colours + if (XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_TWOSIDEDLIGHTING)) { + LOG_TEST_CASE("Two sided lighting"); + // VFACE is positive for clockwise faces + // If Xbox designates counter-clockwise as front-facing, we invert VFACE + auto cwFrontface = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_FRONTFACE) == 0x900; // clockwise; + frontfaceFactor = cwFrontface ? 1 : -1; + } + fColor[PSH_XBOX_CONSTANT_FRONTFACE_FACTOR].r = frontfaceFactor; + // Assume all constants are in use (this is much easier than tracking them for no other purpose than to skip a few here) // Read the color from the corresponding render state slot : // Set all host constant values using a single call: