diff options
Diffstat (limited to 'src/video_core/swrasterizer')
-rw-r--r-- | src/video_core/swrasterizer/clipper.cpp | 4 | ||||
-rw-r--r-- | src/video_core/swrasterizer/framebuffer.cpp | 2 | ||||
-rw-r--r-- | src/video_core/swrasterizer/lighting.cpp | 88 | ||||
-rw-r--r-- | src/video_core/swrasterizer/lighting.h | 3 | ||||
-rw-r--r-- | src/video_core/swrasterizer/rasterizer.cpp | 4 | ||||
-rw-r--r-- | src/video_core/swrasterizer/rasterizer.h | 6 | ||||
-rw-r--r-- | src/video_core/swrasterizer/texturing.cpp | 4 |
7 files changed, 85 insertions, 26 deletions
diff --git a/src/video_core/swrasterizer/clipper.cpp b/src/video_core/swrasterizer/clipper.cpp index 7537689b7..cdbc71502 100644 --- a/src/video_core/swrasterizer/clipper.cpp +++ b/src/video_core/swrasterizer/clipper.cpp @@ -125,10 +125,6 @@ void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const Outpu {Math::MakeVec(f0, f0, f0, -f1), Math::Vec4<float24>(f0, f0, f0, EPSILON)}, // w = EPSILON }}; - // TODO: If one vertex lies outside one of the depth clipping planes, some platforms (e.g. Wii) - // drop the whole primitive instead of clipping the primitive properly. We should test if - // this happens on the 3DS, too. - // Simple implementation of the Sutherland-Hodgman clipping algorithm. // TODO: Make this less inefficient (currently lots of useless buffering overhead happens here) for (auto edge : clipping_edges) { diff --git a/src/video_core/swrasterizer/framebuffer.cpp b/src/video_core/swrasterizer/framebuffer.cpp index 7de3aac75..f34eab6cf 100644 --- a/src/video_core/swrasterizer/framebuffer.cpp +++ b/src/video_core/swrasterizer/framebuffer.cpp @@ -352,6 +352,8 @@ u8 LogicOp(u8 src, u8 dest, FramebufferRegs::LogicOp op) { case FramebufferRegs::LogicOp::OrInverted: return ~src | dest; } + + UNREACHABLE(); }; } // namespace Rasterizer diff --git a/src/video_core/swrasterizer/lighting.cpp b/src/video_core/swrasterizer/lighting.cpp index d61e6d572..5fa748611 100644 --- a/src/video_core/swrasterizer/lighting.cpp +++ b/src/video_core/swrasterizer/lighting.cpp @@ -22,18 +22,37 @@ static float LookupLightingLut(const Pica::State::Lighting& lighting, size_t lut std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors( const Pica::LightingRegs& lighting, const Pica::State::Lighting& lighting_state, - const Math::Quaternion<float>& normquat, const Math::Vec3<float>& view) { + const Math::Quaternion<float>& normquat, const Math::Vec3<float>& view, + const Math::Vec4<u8> (&texture_color)[4]) { - // TODO(Subv): Bump mapping - Math::Vec3<float> surface_normal = {0.0f, 0.0f, 1.0f}; + Math::Vec3<float> surface_normal; + Math::Vec3<float> surface_tangent; if (lighting.config0.bump_mode != LightingRegs::LightingBumpMode::None) { - LOG_CRITICAL(HW_GPU, "unimplemented bump mapping"); - UNIMPLEMENTED(); + Math::Vec3<float> perturbation = + texture_color[lighting.config0.bump_selector].xyz().Cast<float>() / 127.5f - + Math::MakeVec(1.0f, 1.0f, 1.0f); + if (lighting.config0.bump_mode == LightingRegs::LightingBumpMode::NormalMap) { + if (!lighting.config0.disable_bump_renorm) { + const float z_square = 1 - perturbation.xy().Length2(); + perturbation.z = std::sqrt(std::max(z_square, 0.0f)); + } + surface_normal = perturbation; + surface_tangent = Math::MakeVec(1.0f, 0.0f, 0.0f); + } else if (lighting.config0.bump_mode == LightingRegs::LightingBumpMode::TangentMap) { + surface_normal = Math::MakeVec(0.0f, 0.0f, 1.0f); + surface_tangent = perturbation; + } else { + LOG_ERROR(HW_GPU, "Unknown bump mode %u", lighting.config0.bump_mode.Value()); + } + } else { + surface_normal = Math::MakeVec(0.0f, 0.0f, 1.0f); + surface_tangent = Math::MakeVec(1.0f, 0.0f, 0.0f); } // Use the normalized the quaternion when performing the rotation auto normal = Math::QuaternionRotate(normquat, surface_normal); + auto tangent = Math::QuaternionRotate(normquat, surface_tangent); Math::Vec4<float> diffuse_sum = {0.0f, 0.0f, 0.0f, 1.0f}; Math::Vec4<float> specular_sum = {0.0f, 0.0f, 0.0f, 1.0f}; @@ -55,6 +74,9 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors( light_vector.Normalize(); + Math::Vec3<float> norm_view = view.Normalized(); + Math::Vec3<float> half_vector = norm_view + light_vector; + float dist_atten = 1.0f; if (!lighting.IsDistAttenDisabled(num)) { auto distance = (-view - position).Length(); @@ -74,17 +96,15 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors( auto GetLutValue = [&](LightingRegs::LightingLutInput input, bool abs, LightingRegs::LightingScale scale_enum, LightingRegs::LightingSampler sampler) { - Math::Vec3<float> norm_view = view.Normalized(); - Math::Vec3<float> half_angle = (norm_view + light_vector).Normalized(); float result = 0.0f; switch (input) { case LightingRegs::LightingLutInput::NH: - result = Math::Dot(normal, half_angle); + result = Math::Dot(normal, half_vector.Normalized()); break; case LightingRegs::LightingLutInput::VH: - result = Math::Dot(norm_view, half_angle); + result = Math::Dot(norm_view, half_vector.Normalized()); break; case LightingRegs::LightingLutInput::NV: @@ -95,6 +115,22 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors( result = Math::Dot(light_vector, normal); break; + case LightingRegs::LightingLutInput::SP: { + Math::Vec3<s32> spot_dir{light_config.spot_x.Value(), light_config.spot_y.Value(), + light_config.spot_z.Value()}; + result = Math::Dot(light_vector, spot_dir.Cast<float>() / 2047.0f); + break; + } + case LightingRegs::LightingLutInput::CP: + if (lighting.config0.config == LightingRegs::LightingConfig::Config7) { + const Math::Vec3<float> norm_half_vector = half_vector.Normalized(); + const Math::Vec3<float> half_vector_proj = + norm_half_vector - normal * Math::Dot(normal, norm_half_vector); + result = Math::Dot(half_vector_proj, tangent); + } else { + result = 0.0f; + } + break; default: LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %u\n", static_cast<u32>(input)); UNIMPLEMENTED(); @@ -125,6 +161,16 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors( LookupLightingLut(lighting_state, static_cast<size_t>(sampler), index, delta); }; + // If enabled, compute spot light attenuation value + float spot_atten = 1.0f; + if (!lighting.IsSpotAttenDisabled(num) && + LightingRegs::IsLightingSamplerSupported( + lighting.config0.config, LightingRegs::LightingSampler::SpotlightAttenuation)) { + auto lut = LightingRegs::SpotlightAttenuationSampler(num); + spot_atten = GetLutValue(lighting.lut_input.sp, lighting.abs_lut_input.disable_sp == 0, + lighting.lut_scale.sp, lut); + } + // Specular 0 component float d0_lut_value = 1.0f; if (lighting.config1.disable_lut_d0 == 0 && @@ -184,7 +230,8 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors( d1_lut_value * refl_value * light_config.specular_1.ToVec3f(); // Fresnel - if (lighting.config1.disable_lut_fr == 0 && + // Note: only the last entry in the light slots applies the Fresnel factor + if (light_index == lighting.max_light_index && lighting.config1.disable_lut_fr == 0 && LightingRegs::IsLightingSamplerSupported(lighting.config0.config, LightingRegs::LightingSampler::Fresnel)) { @@ -196,14 +243,14 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors( if (lighting.config0.fresnel_selector == LightingRegs::LightingFresnelSelector::PrimaryAlpha || lighting.config0.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) { - diffuse_sum.a() *= lut_value; + diffuse_sum.a() = lut_value; } // Enabled for the specular lighting alpha component if (lighting.config0.fresnel_selector == LightingRegs::LightingFresnelSelector::SecondaryAlpha || lighting.config0.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) { - specular_sum.a() *= lut_value; + specular_sum.a() = lut_value; } } @@ -224,12 +271,23 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors( else dot_product = std::max(dot_product, 0.0f); + if (light_config.config.geometric_factor_0 || light_config.config.geometric_factor_1) { + float geo_factor = half_vector.Length2(); + geo_factor = geo_factor == 0.0f ? 0.0f : std::min(dot_product / geo_factor, 1.0f); + if (light_config.config.geometric_factor_0) { + specular_0 *= geo_factor; + } + if (light_config.config.geometric_factor_1) { + specular_1 *= geo_factor; + } + } + auto diffuse = light_config.diffuse.ToVec3f() * dot_product + light_config.ambient.ToVec3f(); - diffuse_sum += Math::MakeVec(diffuse * dist_atten, 0.0f); + diffuse_sum += Math::MakeVec(diffuse * dist_atten * spot_atten, 0.0f); - specular_sum += - Math::MakeVec((specular_0 + specular_1) * clamp_highlights * dist_atten, 0.0f); + specular_sum += Math::MakeVec( + (specular_0 + specular_1) * clamp_highlights * dist_atten * spot_atten, 0.0f); } diffuse_sum += Math::MakeVec(lighting.global_ambient.ToVec3f(), 0.0f); diff --git a/src/video_core/swrasterizer/lighting.h b/src/video_core/swrasterizer/lighting.h index 438dca926..d807a3d94 100644 --- a/src/video_core/swrasterizer/lighting.h +++ b/src/video_core/swrasterizer/lighting.h @@ -13,6 +13,7 @@ namespace Pica { std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors( const Pica::LightingRegs& lighting, const Pica::State::Lighting& lighting_state, - const Math::Quaternion<float>& normquat, const Math::Vec3<float>& view); + const Math::Quaternion<float>& normquat, const Math::Vec3<float>& view, + const Math::Vec4<u8> (&texture_color)[4]); } // namespace Pica diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp index fdc1df199..862135614 100644 --- a/src/video_core/swrasterizer/rasterizer.cpp +++ b/src/video_core/swrasterizer/rasterizer.cpp @@ -437,8 +437,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve GetInterpolatedAttribute(v0.view.y, v1.view.y, v2.view.y).ToFloat32(), GetInterpolatedAttribute(v0.view.z, v1.view.z, v2.view.z).ToFloat32(), }; - std::tie(primary_fragment_color, secondary_fragment_color) = - ComputeFragmentsColors(g_state.regs.lighting, g_state.lighting, normquat, view); + std::tie(primary_fragment_color, secondary_fragment_color) = ComputeFragmentsColors( + g_state.regs.lighting, g_state.lighting, normquat, view, texture_color); } for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); diff --git a/src/video_core/swrasterizer/rasterizer.h b/src/video_core/swrasterizer/rasterizer.h index 2f0877581..66cd6cfd4 100644 --- a/src/video_core/swrasterizer/rasterizer.h +++ b/src/video_core/swrasterizer/rasterizer.h @@ -19,10 +19,9 @@ struct Vertex : Shader::OutputVertex { // Linear interpolation // factor: 0=this, 1=vtx + // Note: This function cannot be called after perspective divide void Lerp(float24 factor, const Vertex& vtx) { pos = pos * factor + vtx.pos * (float24::FromFloat32(1) - factor); - - // TODO: Should perform perspective correct interpolation here... quat = quat * factor + vtx.quat * (float24::FromFloat32(1) - factor); color = color * factor + vtx.color * (float24::FromFloat32(1) - factor); tc0 = tc0 * factor + vtx.tc0 * (float24::FromFloat32(1) - factor); @@ -30,12 +29,11 @@ struct Vertex : Shader::OutputVertex { tc0_w = tc0_w * factor + vtx.tc0_w * (float24::FromFloat32(1) - factor); view = view * factor + vtx.view * (float24::FromFloat32(1) - factor); tc2 = tc2 * factor + vtx.tc2 * (float24::FromFloat32(1) - factor); - - screenpos = screenpos * factor + vtx.screenpos * (float24::FromFloat32(1) - factor); } // Linear interpolation // factor: 0=v0, 1=v1 + // Note: This function cannot be called after perspective divide static Vertex Lerp(float24 factor, const Vertex& v0, const Vertex& v1) { Vertex ret = v0; ret.Lerp(factor, v1); diff --git a/src/video_core/swrasterizer/texturing.cpp b/src/video_core/swrasterizer/texturing.cpp index 4f02b93f2..79b1ce841 100644 --- a/src/video_core/swrasterizer/texturing.cpp +++ b/src/video_core/swrasterizer/texturing.cpp @@ -89,6 +89,8 @@ Math::Vec3<u8> GetColorModifier(TevStageConfig::ColorModifier factor, case ColorModifier::OneMinusSourceBlue: return (Math::Vec3<u8>(255, 255, 255) - values.bbb()).Cast<u8>(); } + + UNREACHABLE(); }; u8 GetAlphaModifier(TevStageConfig::AlphaModifier factor, const Math::Vec4<u8>& values) { @@ -119,6 +121,8 @@ u8 GetAlphaModifier(TevStageConfig::AlphaModifier factor, const Math::Vec4<u8>& case AlphaModifier::OneMinusSourceBlue: return 255 - values.b(); } + + UNREACHABLE(); }; Math::Vec3<u8> ColorCombine(TevStageConfig::Operation op, const Math::Vec3<u8> input[3]) { |