From b2f472a2b1f36073b0070b81c08a666380ad180d Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Fri, 9 Jun 2017 13:14:55 -0500
Subject: [PATCH 01/27] SwRasterizer: Implement primary fragment color.

---
 src/video_core/swrasterizer/rasterizer.cpp | 119 ++++++++++++++++++++-
 1 file changed, 114 insertions(+), 5 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index 512e81c08..1ab41c2df 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -13,6 +13,7 @@
 #include "common/logging/log.h"
 #include "common/math_util.h"
 #include "common/microprofile.h"
+#include "common/quaternion.h"
 #include "common/vector_math.h"
 #include "core/hw/gpu.h"
 #include "core/memory.h"
@@ -114,6 +115,86 @@ static std::tuple<float24, float24, PAddr> ConvertCubeCoord(float24 u, float24 v
     return std::make_tuple(x / z * half + half, y / z * half + half, addr);
 }
 
+std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Quaternion<float>& normquat, const Math::Vec3<float>& view) {
+    const auto& lighting = g_state.regs.lighting;
+
+    if (lighting.disable)
+        return {{}, {}};
+
+    // TODO(Subv): Bump mapping
+    Math::Vec3<float> surface_normal = {0.0f, 0.0f, 1.0f};
+
+    if (lighting.config0.bump_mode != LightingRegs::LightingBumpMode::None) {
+        LOG_CRITICAL(HW_GPU, "unimplemented bump mapping");
+        UNIMPLEMENTED();
+    }
+
+    // TODO(Subv): Do we need to normalize the quaternion here?
+    auto normal = Math::QuaternionRotate(normquat, surface_normal);
+
+    Math::Vec3<float> light_vector = {};
+    Math::Vec3<float> diffuse_sum = {};
+    // TODO(Subv): Calculate specular
+    Math::Vec3<float> specular_sum = {};
+
+    for (unsigned light_index = 0; light_index <= lighting.max_light_index; ++light_index) {
+        unsigned num = lighting.light_enable.GetNum(light_index);
+        const auto& light_config = g_state.regs.lighting.light[num];
+
+        Math::Vec3<float> position = {float16::FromRaw(light_config.x).ToFloat32(), float16::FromRaw(light_config.y).ToFloat32(), float16::FromRaw(light_config.z).ToFloat32()};
+
+        if (light_config.config.directional)
+            light_vector = position;
+        else
+            light_vector = position + view;
+
+        light_vector.Normalize();
+
+        auto dot_product = Math::Dot(light_vector, normal);
+
+        if (light_config.config.two_sided_diffuse)
+            dot_product = std::abs(dot_product);
+        else
+            dot_product = std::max(dot_product, 0.0f);
+
+        float dist_atten = 1.0f;
+        if (!lighting.IsDistAttenDisabled(num)) {
+            auto distance = (-view - position).Length();
+            float scale = Pica::float20::FromRaw(light_config.dist_atten_scale).ToFloat32();
+            float bias = Pica::float20::FromRaw(light_config.dist_atten_scale).ToFloat32();
+            size_t lut = static_cast<size_t>(LightingRegs::LightingSampler::DistanceAttenuation) + num;
+
+            float sample_loc = scale * distance + bias;
+            unsigned index_i = static_cast<unsigned>(MathUtil::Clamp(floor(sample_loc * 256), 0.0f, 1.0f));
+
+            float index_f = sample_loc - index_i;
+
+            ASSERT_MSG(lut < g_state.lighting.luts.size(), "Out of range lut");
+
+            float lut_value = g_state.lighting.luts[lut][index_i].ToFloat();
+            float lut_diff = g_state.lighting.luts[lut][index_i].DiffToFloat();
+
+            dist_atten = lut_value + lut_diff * index_f;
+        }
+
+        auto diffuse = light_config.diffuse.ToVec3f() * dot_product + light_config.ambient.ToVec3f();
+        diffuse_sum += diffuse * dist_atten;
+    }
+
+    diffuse_sum += lighting.global_ambient.ToVec3f();
+    return {
+        Math::MakeVec<float>(MathUtil::Clamp(diffuse_sum.x, 0.0f, 1.0f) * 255, MathUtil::Clamp(diffuse_sum.y, 0.0f, 1.0f) * 255, MathUtil::Clamp(diffuse_sum.z, 0.0f, 1.0f) * 255, 255).Cast<u8>(),
+        Math::MakeVec<float>(MathUtil::Clamp(specular_sum.x, 0.0f, 1.0f) * 255, MathUtil::Clamp(specular_sum.y, 0.0f, 1.0f) * 255, MathUtil::Clamp(specular_sum.z, 0.0f, 1.0f) * 255, 255).Cast<u8>()
+    };
+}
+
+static bool AreQuaternionsOpposite(Math::Vec4<Pica::float24> qa, Math::Vec4<Pica::float24> qb) {
+    Math::Vec4f a{ qa.x.ToFloat32(), qa.y.ToFloat32(), qa.z.ToFloat32(), qa.w.ToFloat32() };
+    Math::Vec4f b{ qb.x.ToFloat32(), qb.y.ToFloat32(), qb.z.ToFloat32(), qb.w.ToFloat32() };
+
+    return (Math::Dot(a, b) < 0.f);
+}
+
 MICROPROFILE_DEFINE(GPU_Rasterization, "GPU", "Rasterization", MP_RGB(50, 50, 240));
 
 /**
@@ -207,6 +288,15 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
     int bias2 =
         IsRightSideOrFlatBottomEdge(vtxpos[2].xy(), vtxpos[0].xy(), vtxpos[1].xy()) ? -1 : 0;
 
+    // Flip the quaternions if they are opposite to prevent interpolating them over the wrong direction.
+    auto v1_quat = v1.quat;
+    auto v2_quat = v2.quat;
+
+    if (AreQuaternionsOpposite(v0.quat, v1.quat))
+        v1_quat = v1_quat * float24::FromFloat32(-1.0f);
+    if (AreQuaternionsOpposite(v0.quat, v2.quat))
+        v2_quat = v2_quat * float24::FromFloat32(-1.0f);
+
     auto w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w);
 
     auto textures = regs.texturing.GetTextures();
@@ -305,6 +395,21 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
                     255),
             };
 
+            Math::Quaternion<float> normquat{
+                {
+                    GetInterpolatedAttribute(v0.quat.x, v1_quat.x, v2_quat.x).ToFloat32(),
+                    GetInterpolatedAttribute(v0.quat.y, v1_quat.y, v2_quat.y).ToFloat32(),
+                    GetInterpolatedAttribute(v0.quat.z, v1_quat.z, v2_quat.z).ToFloat32()
+                },
+                GetInterpolatedAttribute(v0.quat.w, v1_quat.w, v2_quat.w).ToFloat32(),
+            };
+
+            Math::Vec3<float> fragment_position{
+                GetInterpolatedAttribute(v0.view.x, v1.view.x, v2.view.x).ToFloat32(),
+                GetInterpolatedAttribute(v0.view.y, v1.view.y, v2.view.y).ToFloat32(),
+                GetInterpolatedAttribute(v0.view.z, v1.view.z, v2.view.z).ToFloat32()
+            };
+
             Math::Vec2<float24> uv[3];
             uv[0].u() = GetInterpolatedAttribute(v0.tc0.u(), v1.tc0.u(), v2.tc0.u());
             uv[0].v() = GetInterpolatedAttribute(v0.tc0.v(), v1.tc0.v(), v2.tc0.v());
@@ -419,6 +524,11 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
                 regs.texturing.tev_combiner_buffer_color.a,
             };
 
+            Math::Vec4<u8> primary_fragment_color;
+            Math::Vec4<u8> secondary_fragment_color;
+
+            std::tie(primary_fragment_color, secondary_fragment_color) = ComputeFragmentsColors(normquat, fragment_position);
+
             for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size();
                  ++tev_stage_index) {
                 const auto& tev_stage = tev_stages[tev_stage_index];
@@ -427,14 +537,13 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
                 auto GetSource = [&](Source source) -> Math::Vec4<u8> {
                     switch (source) {
                     case Source::PrimaryColor:
-
-                    // HACK: Until we implement fragment lighting, use primary_color
-                    case Source::PrimaryFragmentColor:
                         return primary_color;
 
-                    // HACK: Until we implement fragment lighting, use zero
+                    case Source::PrimaryFragmentColor:
+                        return primary_fragment_color;
+
                     case Source::SecondaryFragmentColor:
-                        return {0, 0, 0, 0};
+                        return secondary_fragment_color;
 
                     case Source::Texture0:
                         return texture_color[0];

From be25e78b07140cb745387f757001dd04b3b4cc64 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Fri, 9 Jun 2017 14:25:41 -0500
Subject: [PATCH 02/27] SwRasterizer: Calculate specular_0 for fragment
 lighting.

---
 src/video_core/swrasterizer/rasterizer.cpp | 115 ++++++++++++++++++---
 1 file changed, 98 insertions(+), 17 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index 1ab41c2df..34b84b0af 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -115,6 +115,20 @@ static std::tuple<float24, float24, PAddr> ConvertCubeCoord(float24 u, float24 v
     return std::make_tuple(x / z * half + half, y / z * half + half, addr);
 }
 
+
+float LookupLightingLut(size_t lut_index, float index) {
+    unsigned index_i = static_cast<unsigned>(MathUtil::Clamp(floor(index * 256), 0.0f, 1.0f));
+
+    float index_f = index - index_i;
+
+    ASSERT_MSG(lut_index < g_state.lighting.luts.size(), "Out of range lut");
+
+    float lut_value = g_state.lighting.luts[lut_index][index_i].ToFloat();
+    float lut_diff = g_state.lighting.luts[lut_index][index_i].DiffToFloat();
+
+    return lut_value + lut_diff * index_f;
+}
+
 std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Quaternion<float>& normquat, const Math::Vec3<float>& view) {
     const auto& lighting = g_state.regs.lighting;
 
@@ -133,9 +147,9 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
     auto normal = Math::QuaternionRotate(normquat, surface_normal);
 
     Math::Vec3<float> light_vector = {};
-    Math::Vec3<float> diffuse_sum = {};
+    Math::Vec4<float> diffuse_sum = {0.f, 0.f, 0.f, 1.f};
     // TODO(Subv): Calculate specular
-    Math::Vec3<float> specular_sum = {};
+    Math::Vec4<float> specular_sum = {0.f, 0.f, 0.f, 1.f};
 
     for (unsigned light_index = 0; light_index <= lighting.max_light_index; ++light_index) {
         unsigned num = lighting.light_enable.GetNum(light_index);
@@ -150,7 +164,8 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
 
         light_vector.Normalize();
 
-        auto dot_product = Math::Dot(light_vector, normal);
+        auto LV_N = Math::Dot(light_vector, normal);
+        auto dot_product = LV_N;
 
         if (light_config.config.two_sided_diffuse)
             dot_product = std::abs(dot_product);
@@ -165,26 +180,92 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
             size_t lut = static_cast<size_t>(LightingRegs::LightingSampler::DistanceAttenuation) + num;
 
             float sample_loc = scale * distance + bias;
-            unsigned index_i = static_cast<unsigned>(MathUtil::Clamp(floor(sample_loc * 256), 0.0f, 1.0f));
-
-            float index_f = sample_loc - index_i;
-
-            ASSERT_MSG(lut < g_state.lighting.luts.size(), "Out of range lut");
-
-            float lut_value = g_state.lighting.luts[lut][index_i].ToFloat();
-            float lut_diff = g_state.lighting.luts[lut][index_i].DiffToFloat();
-
-            dist_atten = lut_value + lut_diff * index_f;
+            dist_atten = LookupLightingLut(lut, sample_loc);
         }
 
+        float clamp_highlights = 1.0f;
+
+        if (lighting.config0.clamp_highlights) {
+            if (LV_N <= 0.f)
+                clamp_highlights = 0.f;
+            else
+                clamp_highlights = 1.f;
+        }
+
+        auto GetLutIndex = [&](unsigned num, LightingRegs::LightingLutInput input,
+                              bool abs) -> float {
+
+            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);
+                break;
+
+            case LightingRegs::LightingLutInput::VH:
+                result = Math::Dot(norm_view, half_angle);
+                break;
+
+            case LightingRegs::LightingLutInput::NV:
+                result = Math::Dot(normal, norm_view);
+                break;
+
+            case LightingRegs::LightingLutInput::LN:
+                result = Math::Dot(light_vector, normal);
+                break;
+
+            default:
+                LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %d\n", (int)input);
+                UNIMPLEMENTED();
+                result = 0.f;
+            }
+
+            if (abs) {
+                if (light_config.config.two_sided_diffuse)
+                    result = std::abs(result);
+                else
+                    result = std::max(result, 0.0f);
+            } else {
+                if (result < 0.f)
+                    result += 2.f;
+
+                result /= 2.f;
+            }
+
+            return MathUtil::Clamp(result, 0.0f, 1.0f);
+        };
+
+        // Specular 0 component
+        float d0_lut_value = 1.0f;
+        if (lighting.config1.disable_lut_d0 == 0 &&
+            LightingRegs::IsLightingSamplerSupported(
+                lighting.config0.config, LightingRegs::LightingSampler::Distribution0)) {
+
+            // Lookup specular "distribution 0" LUT value
+            float index = GetLutIndex(num, lighting.lut_input.d0.Value(), lighting.abs_lut_input.disable_d0 == 0);
+
+            float scale = lighting.lut_scale.GetScale(lighting.lut_scale.d0);
+
+            d0_lut_value = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Distribution0), index);
+        }
+
+        Math::Vec3<float> specular_0 = d0_lut_value * light_config.specular_0.ToVec3f();
+
+        // TODO(Subv): Specular 1
+        Math::Vec3<float> specular_1 = {};
+
         auto diffuse = light_config.diffuse.ToVec3f() * dot_product + light_config.ambient.ToVec3f();
-        diffuse_sum += diffuse * dist_atten;
+        diffuse_sum += Math::MakeVec(diffuse * dist_atten, 0.0f);
+
+        specular_sum += Math::MakeVec((specular_0 + specular_1) * clamp_highlights * dist_atten, 0.f);
     }
 
-    diffuse_sum += lighting.global_ambient.ToVec3f();
+    diffuse_sum += Math::MakeVec(lighting.global_ambient.ToVec3f(), 0.0f);
     return {
-        Math::MakeVec<float>(MathUtil::Clamp(diffuse_sum.x, 0.0f, 1.0f) * 255, MathUtil::Clamp(diffuse_sum.y, 0.0f, 1.0f) * 255, MathUtil::Clamp(diffuse_sum.z, 0.0f, 1.0f) * 255, 255).Cast<u8>(),
-        Math::MakeVec<float>(MathUtil::Clamp(specular_sum.x, 0.0f, 1.0f) * 255, MathUtil::Clamp(specular_sum.y, 0.0f, 1.0f) * 255, MathUtil::Clamp(specular_sum.z, 0.0f, 1.0f) * 255, 255).Cast<u8>()
+        Math::MakeVec<float>(MathUtil::Clamp(diffuse_sum.x, 0.0f, 1.0f) * 255, MathUtil::Clamp(diffuse_sum.y, 0.0f, 1.0f) * 255, MathUtil::Clamp(diffuse_sum.z, 0.0f, 1.0f) * 255, MathUtil::Clamp(diffuse_sum.w, 0.0f, 1.0f) * 255).Cast<u8>(),
+        Math::MakeVec<float>(MathUtil::Clamp(specular_sum.x, 0.0f, 1.0f) * 255, MathUtil::Clamp(specular_sum.y, 0.0f, 1.0f) * 255, MathUtil::Clamp(specular_sum.z, 0.0f, 1.0f) * 255, MathUtil::Clamp(specular_sum.w, 0.0f, 1.0f) * 255).Cast<u8>()
     };
 }
 

From 46b8c8e1da6bc29df2662d63b0e028136fef3636 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Fri, 9 Jun 2017 14:44:02 -0500
Subject: [PATCH 03/27] SwRasterizer: Calculate specular_1 for fragment
 lighting.

---
 src/video_core/swrasterizer/rasterizer.cpp | 62 ++++++++++++++++++++--
 1 file changed, 59 insertions(+), 3 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index 34b84b0af..e0c326a4a 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -148,8 +148,8 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
 
     Math::Vec3<float> light_vector = {};
     Math::Vec4<float> diffuse_sum = {0.f, 0.f, 0.f, 1.f};
-    // TODO(Subv): Calculate specular
     Math::Vec4<float> specular_sum = {0.f, 0.f, 0.f, 1.f};
+    Math::Vec3<float> refl_value = {};
 
     for (unsigned light_index = 0; light_index <= lighting.max_light_index; ++light_index) {
         unsigned num = lighting.light_enable.GetNum(light_index);
@@ -253,8 +253,64 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
 
         Math::Vec3<float> specular_0 = d0_lut_value * light_config.specular_0.ToVec3f();
 
-        // TODO(Subv): Specular 1
-        Math::Vec3<float> specular_1 = {};
+        // If enabled, lookup ReflectRed value, otherwise, 1.0 is used
+        if (lighting.config1.disable_lut_rr == 0 &&
+            LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
+                                                     LightingRegs::LightingSampler::ReflectRed)) {
+
+            float index = GetLutIndex(num, lighting.lut_input.rr, lighting.abs_lut_input.disable_rr == 0);
+
+            float scale = lighting.lut_scale.GetScale(lighting.lut_scale.rr);
+
+            refl_value.x = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectRed), index);
+        } else {
+            refl_value.x = 1.0f;
+        }
+
+        // If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used
+        if (lighting.config1.disable_lut_rg == 0 &&
+            LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
+                                                     LightingRegs::LightingSampler::ReflectGreen)) {
+
+            float index = GetLutIndex(num, lighting.lut_input.rg, lighting.abs_lut_input.disable_rg == 0);
+
+            float scale = lighting.lut_scale.GetScale(lighting.lut_scale.rg);
+
+            refl_value.y = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectGreen), index);
+        } else {
+            refl_value.y = refl_value.x;
+        }
+
+        // If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used
+        if (lighting.config1.disable_lut_rb == 0 &&
+            LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
+                                                     LightingRegs::LightingSampler::ReflectBlue)) {
+
+            float index = GetLutIndex(num, lighting.lut_input.rb, lighting.abs_lut_input.disable_rb == 0);
+
+            float scale = lighting.lut_scale.GetScale(lighting.lut_scale.rb);
+
+            refl_value.z = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectBlue), index);
+        } else {
+            refl_value.z = refl_value.x;
+        }
+
+        float d1_lut_value = 1.0f;
+        if (lighting.config1.disable_lut_d1 == 0 &&
+            LightingRegs::IsLightingSamplerSupported(
+                lighting.config0.config, LightingRegs::LightingSampler::Distribution1)) {
+
+            // Lookup specular "distribution 1" LUT value
+            float index = GetLutIndex(num, lighting.lut_input.d1.Value(), lighting.abs_lut_input.disable_d1 == 0);
+
+            float scale = lighting.lut_scale.GetScale(lighting.lut_scale.d1);
+
+            d1_lut_value = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Distribution1), index);
+        }
+
+        Math::Vec3<float> specular_1 = d1_lut_value * refl_value * light_config.specular_1.ToVec3f();
+
+        // TODO(Subv): Fresnel
 
         auto diffuse = light_config.diffuse.ToVec3f() * dot_product + light_config.ambient.ToVec3f();
         diffuse_sum += Math::MakeVec(diffuse * dist_atten, 0.0f);

From 10b0bea06008fea89564dc5ef8895c0274f8ef18 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Fri, 9 Jun 2017 14:55:54 -0500
Subject: [PATCH 04/27] SwRasterizer: Calculate fresnel for fragment lighting.

---
 src/video_core/swrasterizer/rasterizer.cpp | 26 +++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index e0c326a4a..2d1daa24a 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -310,7 +310,31 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
 
         Math::Vec3<float> specular_1 = d1_lut_value * refl_value * light_config.specular_1.ToVec3f();
 
-        // TODO(Subv): Fresnel
+        if (lighting.config1.disable_lut_fr == 0 &&
+            LightingRegs::IsLightingSamplerSupported(
+                lighting.config0.config, LightingRegs::LightingSampler::Fresnel)) {
+
+            // Lookup fresnel LUT value
+            float index = GetLutIndex(num, lighting.lut_input.fr.Value(), lighting.abs_lut_input.disable_fr == 0);
+
+            float scale = lighting.lut_scale.GetScale(lighting.lut_scale.fr);
+
+            float lut_value = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Fresnel), index);
+
+            // Enabled for difffuse lighting alpha component
+            if (lighting.config0.fresnel_selector == LightingRegs::LightingFresnelSelector::PrimaryAlpha ||
+                lighting.config0.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) {
+                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;
+            }
+        }
+
 
         auto diffuse = light_config.diffuse.ToVec3f() * dot_product + light_config.ambient.ToVec3f();
         diffuse_sum += Math::MakeVec(diffuse * dist_atten, 0.0f);

From 80b6fc592e3a2f5821975e84b5df35f5dc4ae51a Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Fri, 9 Jun 2017 15:24:28 -0500
Subject: [PATCH 05/27] SwRasterizer: Fixed the lighting lut lookup function.

---
 src/video_core/swrasterizer/rasterizer.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index 2d1daa24a..2b85ac86c 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -117,7 +117,9 @@ static std::tuple<float24, float24, PAddr> ConvertCubeCoord(float24 u, float24 v
 
 
 float LookupLightingLut(size_t lut_index, float index) {
-    unsigned index_i = static_cast<unsigned>(MathUtil::Clamp(floor(index * 256), 0.0f, 1.0f));
+    index *= 256;
+
+    unsigned index_i = static_cast<unsigned>(MathUtil::Clamp(floor(index), 0.0f, 255.0f));
 
     float index_f = index - index_i;
 
@@ -126,7 +128,7 @@ float LookupLightingLut(size_t lut_index, float index) {
     float lut_value = g_state.lighting.luts[lut_index][index_i].ToFloat();
     float lut_diff = g_state.lighting.luts[lut_index][index_i].DiffToFloat();
 
-    return lut_value + lut_diff * index_f;
+    return lut_value + lut_diff * index_f / 256.f;
 }
 
 std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Quaternion<float>& normquat, const Math::Vec3<float>& view) {

From f2d4d5c2191275bd91f2f42b880f3edf3bccfd63 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Fri, 9 Jun 2017 17:33:25 -0500
Subject: [PATCH 06/27] SwRasterizer: Corrected the light LUT lookups.

---
 src/common/quaternion.h                    |  5 ++
 src/video_core/swrasterizer/rasterizer.cpp | 76 ++++++++++++----------
 2 files changed, 48 insertions(+), 33 deletions(-)

diff --git a/src/common/quaternion.h b/src/common/quaternion.h
index 84ac82ed3..77f626bcb 100644
--- a/src/common/quaternion.h
+++ b/src/common/quaternion.h
@@ -30,6 +30,11 @@ public:
         return {xyz * other.w + other.xyz * w + Cross(xyz, other.xyz),
                 w * other.w - Dot(xyz, other.xyz)};
     }
+
+    Quaternion<T> Normalized() const {
+        T length = std::sqrt(xyz.Length2() + w * w);
+        return {xyz / length, w / length};
+    }
 };
 
 template <typename T>
diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index 2b85ac86c..a9098e1f0 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -115,20 +115,14 @@ static std::tuple<float24, float24, PAddr> ConvertCubeCoord(float24 u, float24 v
     return std::make_tuple(x / z * half + half, y / z * half + half, addr);
 }
 
-
-float LookupLightingLut(size_t lut_index, float index) {
-    index *= 256;
-
-    unsigned index_i = static_cast<unsigned>(MathUtil::Clamp(floor(index), 0.0f, 255.0f));
-
-    float index_f = index - index_i;
-
+float LookupLightingLut(size_t lut_index, u8 index, float delta) {
     ASSERT_MSG(lut_index < g_state.lighting.luts.size(), "Out of range lut");
+    ASSERT_MSG(index < g_state.lighting.luts[0].size(), "Out of range index");
 
-    float lut_value = g_state.lighting.luts[lut_index][index_i].ToFloat();
-    float lut_diff = g_state.lighting.luts[lut_index][index_i].DiffToFloat();
+    float lut_value = g_state.lighting.luts[lut_index][index].ToFloat();
+    float lut_diff = g_state.lighting.luts[lut_index][index].DiffToFloat();
 
-    return lut_value + lut_diff * index_f / 256.f;
+    return lut_value + lut_diff * delta;
 }
 
 std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Quaternion<float>& normquat, const Math::Vec3<float>& view) {
@@ -145,8 +139,8 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
         UNIMPLEMENTED();
     }
 
-    // TODO(Subv): Do we need to normalize the quaternion here?
-    auto normal = Math::QuaternionRotate(normquat, surface_normal);
+    // Use the normalized the quaternion when performing the rotation
+    auto normal = Math::QuaternionRotate(normquat.Normalized(), surface_normal);
 
     Math::Vec3<float> light_vector = {};
     Math::Vec4<float> diffuse_sum = {0.f, 0.f, 0.f, 1.f};
@@ -182,7 +176,10 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
             size_t lut = static_cast<size_t>(LightingRegs::LightingSampler::DistanceAttenuation) + num;
 
             float sample_loc = scale * distance + bias;
-            dist_atten = LookupLightingLut(lut, sample_loc);
+
+            u8 lutindex = MathUtil::Clamp(floorf(sample_loc * 256.f), 0.0f, 255.0f);
+            float delta = sample_loc * 256 - lutindex;
+            dist_atten = LookupLightingLut(lut, lutindex, delta / 256.f);
         }
 
         float clamp_highlights = 1.0f;
@@ -195,7 +192,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
         }
 
         auto GetLutIndex = [&](unsigned num, LightingRegs::LightingLutInput input,
-                              bool abs) -> float {
+                              bool abs) -> std::tuple<u8, float> {
 
             Math::Vec3<float> norm_view = view.Normalized();
             Math::Vec3<float> half_angle = (norm_view + light_vector).Normalized();
@@ -229,14 +226,15 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
                     result = std::abs(result);
                 else
                     result = std::max(result, 0.0f);
+
+                u8 lutindex = MathUtil::Clamp(floorf(result * 256.f), 0.0f, 255.0f);
+                float delta = result * 256 - lutindex;
+                return { lutindex, delta / 256.f };
             } else {
-                if (result < 0.f)
-                    result += 2.f;
-
-                result /= 2.f;
+                u8 tmpi = MathUtil::Clamp(floorf(result * 128.f), 0.0f, 127.0f);
+                float delta = result * 128.f - tmpi;
+                return { tmpi & 0xFF, delta / 128.f };
             }
-
-            return MathUtil::Clamp(result, 0.0f, 1.0f);
         };
 
         // Specular 0 component
@@ -246,11 +244,13 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
                 lighting.config0.config, LightingRegs::LightingSampler::Distribution0)) {
 
             // Lookup specular "distribution 0" LUT value
-            float index = GetLutIndex(num, lighting.lut_input.d0.Value(), lighting.abs_lut_input.disable_d0 == 0);
+            u8 index;
+            float delta;
+            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.d0.Value(), lighting.abs_lut_input.disable_d0 == 0);
 
             float scale = lighting.lut_scale.GetScale(lighting.lut_scale.d0);
 
-            d0_lut_value = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Distribution0), index);
+            d0_lut_value = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Distribution0), index, delta);
         }
 
         Math::Vec3<float> specular_0 = d0_lut_value * light_config.specular_0.ToVec3f();
@@ -260,11 +260,13 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
             LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
                                                      LightingRegs::LightingSampler::ReflectRed)) {
 
-            float index = GetLutIndex(num, lighting.lut_input.rr, lighting.abs_lut_input.disable_rr == 0);
+            u8 index;
+            float delta;
+            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.rr, lighting.abs_lut_input.disable_rr == 0);
 
             float scale = lighting.lut_scale.GetScale(lighting.lut_scale.rr);
 
-            refl_value.x = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectRed), index);
+            refl_value.x = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectRed), index, delta);
         } else {
             refl_value.x = 1.0f;
         }
@@ -274,11 +276,13 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
             LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
                                                      LightingRegs::LightingSampler::ReflectGreen)) {
 
-            float index = GetLutIndex(num, lighting.lut_input.rg, lighting.abs_lut_input.disable_rg == 0);
+            u8 index;
+            float delta;
+            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.rg, lighting.abs_lut_input.disable_rg == 0);
 
             float scale = lighting.lut_scale.GetScale(lighting.lut_scale.rg);
 
-            refl_value.y = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectGreen), index);
+            refl_value.y = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectGreen), index, delta);
         } else {
             refl_value.y = refl_value.x;
         }
@@ -288,11 +292,13 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
             LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
                                                      LightingRegs::LightingSampler::ReflectBlue)) {
 
-            float index = GetLutIndex(num, lighting.lut_input.rb, lighting.abs_lut_input.disable_rb == 0);
+            u8 index;
+            float delta;
+            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.rb, lighting.abs_lut_input.disable_rb == 0);
 
             float scale = lighting.lut_scale.GetScale(lighting.lut_scale.rb);
 
-            refl_value.z = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectBlue), index);
+            refl_value.z = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectBlue), index, delta);
         } else {
             refl_value.z = refl_value.x;
         }
@@ -303,11 +309,13 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
                 lighting.config0.config, LightingRegs::LightingSampler::Distribution1)) {
 
             // Lookup specular "distribution 1" LUT value
-            float index = GetLutIndex(num, lighting.lut_input.d1.Value(), lighting.abs_lut_input.disable_d1 == 0);
+            u8 index;
+            float delta;
+            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.d1.Value(), lighting.abs_lut_input.disable_d1 == 0);
 
             float scale = lighting.lut_scale.GetScale(lighting.lut_scale.d1);
 
-            d1_lut_value = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Distribution1), index);
+            d1_lut_value = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Distribution1), index, delta);
         }
 
         Math::Vec3<float> specular_1 = d1_lut_value * refl_value * light_config.specular_1.ToVec3f();
@@ -317,11 +325,13 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
                 lighting.config0.config, LightingRegs::LightingSampler::Fresnel)) {
 
             // Lookup fresnel LUT value
-            float index = GetLutIndex(num, lighting.lut_input.fr.Value(), lighting.abs_lut_input.disable_fr == 0);
+            u8 index;
+            float delta;
+            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.fr.Value(), lighting.abs_lut_input.disable_fr == 0);
 
             float scale = lighting.lut_scale.GetScale(lighting.lut_scale.fr);
 
-            float lut_value = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Fresnel), index);
+            float lut_value = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Fresnel), index, delta);
 
             // Enabled for difffuse lighting alpha component
             if (lighting.config0.fresnel_selector == LightingRegs::LightingFresnelSelector::PrimaryAlpha ||

From 2a75837bc30ba08e2470f4b91078747a08c5213a Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Fri, 9 Jun 2017 18:18:57 -0500
Subject: [PATCH 07/27] SwRasterizer: Corrected the light LUT lookups.

---
 src/video_core/swrasterizer/rasterizer.cpp | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index a9098e1f0..2c804b6e7 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -177,9 +177,9 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
 
             float sample_loc = scale * distance + bias;
 
-            u8 lutindex = MathUtil::Clamp(floorf(sample_loc * 256.f), 0.0f, 255.0f);
+            u8 lutindex = MathUtil::Clamp(std::floor(sample_loc * 256.f), 0.0f, 255.0f);
             float delta = sample_loc * 256 - lutindex;
-            dist_atten = LookupLightingLut(lut, lutindex, delta / 256.f);
+            dist_atten = LookupLightingLut(lut, lutindex, delta);
         }
 
         float clamp_highlights = 1.0f;
@@ -227,13 +227,14 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
                 else
                     result = std::max(result, 0.0f);
 
-                u8 lutindex = MathUtil::Clamp(floorf(result * 256.f), 0.0f, 255.0f);
+                u8 lutindex = MathUtil::Clamp(std::floor(result * 256.f), 0.0f, 255.0f);
                 float delta = result * 256 - lutindex;
-                return { lutindex, delta / 256.f };
+                return { lutindex, delta };
             } else {
-                u8 tmpi = MathUtil::Clamp(floorf(result * 128.f), 0.0f, 127.0f);
+                float flr = std::floor(result * 128.f);
+                s8 tmpi = MathUtil::Clamp(flr, -128.0f, 127.0f);
                 float delta = result * 128.f - tmpi;
-                return { tmpi & 0xFF, delta / 128.f };
+                return { tmpi & 0xFF, delta };
             }
         };
 

From 73566ff7a990cdfe8d8f023997b57942dc785fc4 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Sun, 11 Jun 2017 11:55:35 -0500
Subject: [PATCH 08/27] SwRasterizer: Flip the vertex quaternions before
 clipping (if necessary).

---
 src/common/vector_math.h                   |  2 +-
 src/video_core/swrasterizer/clipper.cpp    | 11 ++++++++++
 src/video_core/swrasterizer/rasterizer.cpp | 24 ++++------------------
 3 files changed, 16 insertions(+), 21 deletions(-)

diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index c7a461a1e..d0fe0e405 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -462,7 +462,7 @@ public:
         z -= other.z;
         w -= other.w;
     }
-    template <typename Q = T, class = typename std::enable_if<std::is_signed<Q>::value>::type>
+    template <typename Q = T>
     Vec4<decltype(-T{})> operator-() const {
         return MakeVec(-x, -y, -z, -w);
     }
diff --git a/src/video_core/swrasterizer/clipper.cpp b/src/video_core/swrasterizer/clipper.cpp
index 6fb923756..7537689b7 100644
--- a/src/video_core/swrasterizer/clipper.cpp
+++ b/src/video_core/swrasterizer/clipper.cpp
@@ -95,6 +95,17 @@ void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const Outpu
     static const size_t MAX_VERTICES = 9;
     static_vector<Vertex, MAX_VERTICES> buffer_a = {v0, v1, v2};
     static_vector<Vertex, MAX_VERTICES> buffer_b;
+
+    auto FlipQuaternionIfOpposite = [](auto& a, const auto& b) {
+        if (Math::Dot(a, b) < float24::Zero())
+            a = -a;
+    };
+
+    // Flip the quaternions if they are opposite to prevent interpolating them over the wrong
+    // direction.
+    FlipQuaternionIfOpposite(buffer_a[1].quat, buffer_a[0].quat);
+    FlipQuaternionIfOpposite(buffer_a[2].quat, buffer_a[0].quat);
+
     auto* output_list = &buffer_a;
     auto* input_list = &buffer_b;
 
diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index 2c804b6e7..76f793c86 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -362,13 +362,6 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
     };
 }
 
-static bool AreQuaternionsOpposite(Math::Vec4<Pica::float24> qa, Math::Vec4<Pica::float24> qb) {
-    Math::Vec4f a{ qa.x.ToFloat32(), qa.y.ToFloat32(), qa.z.ToFloat32(), qa.w.ToFloat32() };
-    Math::Vec4f b{ qb.x.ToFloat32(), qb.y.ToFloat32(), qb.z.ToFloat32(), qb.w.ToFloat32() };
-
-    return (Math::Dot(a, b) < 0.f);
-}
-
 MICROPROFILE_DEFINE(GPU_Rasterization, "GPU", "Rasterization", MP_RGB(50, 50, 240));
 
 /**
@@ -462,15 +455,6 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
     int bias2 =
         IsRightSideOrFlatBottomEdge(vtxpos[2].xy(), vtxpos[0].xy(), vtxpos[1].xy()) ? -1 : 0;
 
-    // Flip the quaternions if they are opposite to prevent interpolating them over the wrong direction.
-    auto v1_quat = v1.quat;
-    auto v2_quat = v2.quat;
-
-    if (AreQuaternionsOpposite(v0.quat, v1.quat))
-        v1_quat = v1_quat * float24::FromFloat32(-1.0f);
-    if (AreQuaternionsOpposite(v0.quat, v2.quat))
-        v2_quat = v2_quat * float24::FromFloat32(-1.0f);
-
     auto w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w);
 
     auto textures = regs.texturing.GetTextures();
@@ -571,11 +555,11 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
 
             Math::Quaternion<float> normquat{
                 {
-                    GetInterpolatedAttribute(v0.quat.x, v1_quat.x, v2_quat.x).ToFloat32(),
-                    GetInterpolatedAttribute(v0.quat.y, v1_quat.y, v2_quat.y).ToFloat32(),
-                    GetInterpolatedAttribute(v0.quat.z, v1_quat.z, v2_quat.z).ToFloat32()
+                    GetInterpolatedAttribute(v0.quat.x, v1.quat.x, v2.quat.x).ToFloat32(),
+                    GetInterpolatedAttribute(v0.quat.y, v1.quat.y, v2.quat.y).ToFloat32(),
+                    GetInterpolatedAttribute(v0.quat.z, v1.quat.z, v2.quat.z).ToFloat32()
                 },
-                GetInterpolatedAttribute(v0.quat.w, v1_quat.w, v2_quat.w).ToFloat32(),
+                GetInterpolatedAttribute(v0.quat.w, v1.quat.w, v2.quat.w).ToFloat32(),
             };
 
             Math::Vec3<float> fragment_position{

From 2d69a9b8bf232fdd9e3bbb2a9c624ee9dd6ec637 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Tue, 13 Jun 2017 12:31:28 -0500
Subject: [PATCH 09/27] SwRasterizer: Run clang-format

---
 src/video_core/swrasterizer/rasterizer.cpp | 128 +++++++++++++--------
 1 file changed, 83 insertions(+), 45 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index 76f793c86..382b5927b 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -125,11 +125,12 @@ float LookupLightingLut(size_t lut_index, u8 index, float delta) {
     return lut_value + lut_diff * delta;
 }
 
-std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Quaternion<float>& normquat, const Math::Vec3<float>& view) {
+std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
+    const Math::Quaternion<float>& normquat, const Math::Vec3<float>& view) {
     const auto& lighting = g_state.regs.lighting;
 
     if (lighting.disable)
-        return {{}, {}};
+        return {Math::MakeVec<u8>(0, 0, 0, 0), Math::MakeVec<u8>(0, 0, 0, 0)};
 
     // TODO(Subv): Bump mapping
     Math::Vec3<float> surface_normal = {0.0f, 0.0f, 1.0f};
@@ -151,7 +152,9 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
         unsigned num = lighting.light_enable.GetNum(light_index);
         const auto& light_config = g_state.regs.lighting.light[num];
 
-        Math::Vec3<float> position = {float16::FromRaw(light_config.x).ToFloat32(), float16::FromRaw(light_config.y).ToFloat32(), float16::FromRaw(light_config.z).ToFloat32()};
+        Math::Vec3<float> position = {float16::FromRaw(light_config.x).ToFloat32(),
+                                      float16::FromRaw(light_config.y).ToFloat32(),
+                                      float16::FromRaw(light_config.z).ToFloat32()};
 
         if (light_config.config.directional)
             light_vector = position;
@@ -173,11 +176,13 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
             auto distance = (-view - position).Length();
             float scale = Pica::float20::FromRaw(light_config.dist_atten_scale).ToFloat32();
             float bias = Pica::float20::FromRaw(light_config.dist_atten_scale).ToFloat32();
-            size_t lut = static_cast<size_t>(LightingRegs::LightingSampler::DistanceAttenuation) + num;
+            size_t lut =
+                static_cast<size_t>(LightingRegs::LightingSampler::DistanceAttenuation) + num;
 
             float sample_loc = scale * distance + bias;
 
-            u8 lutindex = MathUtil::Clamp(std::floor(sample_loc * 256.f), 0.0f, 255.0f);
+            u8 lutindex =
+                static_cast<u8>(MathUtil::Clamp(std::floor(sample_loc * 256.f), 0.0f, 255.0f));
             float delta = sample_loc * 256 - lutindex;
             dist_atten = LookupLightingLut(lut, lutindex, delta);
         }
@@ -192,7 +197,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
         }
 
         auto GetLutIndex = [&](unsigned num, LightingRegs::LightingLutInput input,
-                              bool abs) -> std::tuple<u8, float> {
+                               bool abs) -> std::tuple<u8, float> {
 
             Math::Vec3<float> norm_view = view.Normalized();
             Math::Vec3<float> half_angle = (norm_view + light_vector).Normalized();
@@ -216,7 +221,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
                 break;
 
             default:
-                LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %d\n", (int)input);
+                LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %u\n", static_cast<u32>(input));
                 UNIMPLEMENTED();
                 result = 0.f;
             }
@@ -227,14 +232,15 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
                 else
                     result = std::max(result, 0.0f);
 
-                u8 lutindex = MathUtil::Clamp(std::floor(result * 256.f), 0.0f, 255.0f);
+                float flr = std::floor(result * 256.f);
+                u8 lutindex = static_cast<u8>(MathUtil::Clamp(flr, 0.0f, 255.0f));
                 float delta = result * 256 - lutindex;
-                return { lutindex, delta };
+                return {lutindex, delta};
             } else {
                 float flr = std::floor(result * 128.f);
-                s8 tmpi = MathUtil::Clamp(flr, -128.0f, 127.0f);
-                float delta = result * 128.f - tmpi;
-                return { tmpi & 0xFF, delta };
+                s8 lutindex = static_cast<u8>(MathUtil::Clamp(flr, -128.0f, 127.0f));
+                float delta = result * 128.f - lutindex;
+                return {static_cast<u8>(lutindex), delta};
             }
         };
 
@@ -247,11 +253,15 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
             // Lookup specular "distribution 0" LUT value
             u8 index;
             float delta;
-            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.d0.Value(), lighting.abs_lut_input.disable_d0 == 0);
+            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.d0.Value(),
+                                                 lighting.abs_lut_input.disable_d0 == 0);
 
             float scale = lighting.lut_scale.GetScale(lighting.lut_scale.d0);
 
-            d0_lut_value = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Distribution0), index, delta);
+            d0_lut_value =
+                scale *
+                LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Distribution0),
+                                  index, delta);
         }
 
         Math::Vec3<float> specular_0 = d0_lut_value * light_config.specular_0.ToVec3f();
@@ -263,11 +273,15 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
 
             u8 index;
             float delta;
-            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.rr, lighting.abs_lut_input.disable_rr == 0);
+            std::tie(index, delta) =
+                GetLutIndex(num, lighting.lut_input.rr, lighting.abs_lut_input.disable_rr == 0);
 
             float scale = lighting.lut_scale.GetScale(lighting.lut_scale.rr);
 
-            refl_value.x = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectRed), index, delta);
+            refl_value.x =
+                scale *
+                LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectRed),
+                                  index, delta);
         } else {
             refl_value.x = 1.0f;
         }
@@ -279,11 +293,15 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
 
             u8 index;
             float delta;
-            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.rg, lighting.abs_lut_input.disable_rg == 0);
+            std::tie(index, delta) =
+                GetLutIndex(num, lighting.lut_input.rg, lighting.abs_lut_input.disable_rg == 0);
 
             float scale = lighting.lut_scale.GetScale(lighting.lut_scale.rg);
 
-            refl_value.y = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectGreen), index, delta);
+            refl_value.y =
+                scale *
+                LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectGreen),
+                                  index, delta);
         } else {
             refl_value.y = refl_value.x;
         }
@@ -295,11 +313,15 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
 
             u8 index;
             float delta;
-            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.rb, lighting.abs_lut_input.disable_rb == 0);
+            std::tie(index, delta) =
+                GetLutIndex(num, lighting.lut_input.rb, lighting.abs_lut_input.disable_rb == 0);
 
             float scale = lighting.lut_scale.GetScale(lighting.lut_scale.rb);
 
-            refl_value.z = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectBlue), index, delta);
+            refl_value.z =
+                scale *
+                LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectBlue),
+                                  index, delta);
         } else {
             refl_value.z = refl_value.x;
         }
@@ -312,54 +334,72 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(const Math::Qu
             // Lookup specular "distribution 1" LUT value
             u8 index;
             float delta;
-            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.d1.Value(), lighting.abs_lut_input.disable_d1 == 0);
+            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.d1.Value(),
+                                                 lighting.abs_lut_input.disable_d1 == 0);
 
             float scale = lighting.lut_scale.GetScale(lighting.lut_scale.d1);
 
-            d1_lut_value = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Distribution1), index, delta);
+            d1_lut_value =
+                scale *
+                LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Distribution1),
+                                  index, delta);
         }
 
-        Math::Vec3<float> specular_1 = d1_lut_value * refl_value * light_config.specular_1.ToVec3f();
+        Math::Vec3<float> specular_1 =
+            d1_lut_value * refl_value * light_config.specular_1.ToVec3f();
 
         if (lighting.config1.disable_lut_fr == 0 &&
-            LightingRegs::IsLightingSamplerSupported(
-                lighting.config0.config, LightingRegs::LightingSampler::Fresnel)) {
+            LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
+                                                     LightingRegs::LightingSampler::Fresnel)) {
 
             // Lookup fresnel LUT value
             u8 index;
             float delta;
-            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.fr.Value(), lighting.abs_lut_input.disable_fr == 0);
+            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.fr.Value(),
+                                                 lighting.abs_lut_input.disable_fr == 0);
 
             float scale = lighting.lut_scale.GetScale(lighting.lut_scale.fr);
 
-            float lut_value = scale * LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Fresnel), index, delta);
+            float lut_value =
+                scale *
+                LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Fresnel),
+                                  index, delta);
 
-            // Enabled for difffuse lighting alpha component
-            if (lighting.config0.fresnel_selector == LightingRegs::LightingFresnelSelector::PrimaryAlpha ||
+            // Enabled for diffuse lighting alpha component
+            if (lighting.config0.fresnel_selector ==
+                    LightingRegs::LightingFresnelSelector::PrimaryAlpha ||
                 lighting.config0.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) {
                 diffuse_sum.a() *= lut_value;
             }
 
             // Enabled for the specular lighting alpha component
             if (lighting.config0.fresnel_selector ==
-                LightingRegs::LightingFresnelSelector::SecondaryAlpha ||
+                    LightingRegs::LightingFresnelSelector::SecondaryAlpha ||
                 lighting.config0.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) {
                 specular_sum.a() *= lut_value;
             }
         }
 
-
-        auto diffuse = light_config.diffuse.ToVec3f() * dot_product + light_config.ambient.ToVec3f();
+        auto diffuse =
+            light_config.diffuse.ToVec3f() * dot_product + light_config.ambient.ToVec3f();
         diffuse_sum += Math::MakeVec(diffuse * dist_atten, 0.0f);
 
-        specular_sum += Math::MakeVec((specular_0 + specular_1) * clamp_highlights * dist_atten, 0.f);
+        specular_sum +=
+            Math::MakeVec((specular_0 + specular_1) * clamp_highlights * dist_atten, 0.f);
     }
 
     diffuse_sum += Math::MakeVec(lighting.global_ambient.ToVec3f(), 0.0f);
-    return {
-        Math::MakeVec<float>(MathUtil::Clamp(diffuse_sum.x, 0.0f, 1.0f) * 255, MathUtil::Clamp(diffuse_sum.y, 0.0f, 1.0f) * 255, MathUtil::Clamp(diffuse_sum.z, 0.0f, 1.0f) * 255, MathUtil::Clamp(diffuse_sum.w, 0.0f, 1.0f) * 255).Cast<u8>(),
-        Math::MakeVec<float>(MathUtil::Clamp(specular_sum.x, 0.0f, 1.0f) * 255, MathUtil::Clamp(specular_sum.y, 0.0f, 1.0f) * 255, MathUtil::Clamp(specular_sum.z, 0.0f, 1.0f) * 255, MathUtil::Clamp(specular_sum.w, 0.0f, 1.0f) * 255).Cast<u8>()
-    };
+
+    return {Math::MakeVec<float>(MathUtil::Clamp(diffuse_sum.x, 0.0f, 1.0f) * 255,
+                                 MathUtil::Clamp(diffuse_sum.y, 0.0f, 1.0f) * 255,
+                                 MathUtil::Clamp(diffuse_sum.z, 0.0f, 1.0f) * 255,
+                                 MathUtil::Clamp(diffuse_sum.w, 0.0f, 1.0f) * 255)
+                .Cast<u8>(),
+            Math::MakeVec<float>(MathUtil::Clamp(specular_sum.x, 0.0f, 1.0f) * 255,
+                                 MathUtil::Clamp(specular_sum.y, 0.0f, 1.0f) * 255,
+                                 MathUtil::Clamp(specular_sum.z, 0.0f, 1.0f) * 255,
+                                 MathUtil::Clamp(specular_sum.w, 0.0f, 1.0f) * 255)
+                .Cast<u8>()};
 }
 
 MICROPROFILE_DEFINE(GPU_Rasterization, "GPU", "Rasterization", MP_RGB(50, 50, 240));
@@ -554,19 +594,16 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
             };
 
             Math::Quaternion<float> normquat{
-                {
-                    GetInterpolatedAttribute(v0.quat.x, v1.quat.x, v2.quat.x).ToFloat32(),
-                    GetInterpolatedAttribute(v0.quat.y, v1.quat.y, v2.quat.y).ToFloat32(),
-                    GetInterpolatedAttribute(v0.quat.z, v1.quat.z, v2.quat.z).ToFloat32()
-                },
+                {GetInterpolatedAttribute(v0.quat.x, v1.quat.x, v2.quat.x).ToFloat32(),
+                 GetInterpolatedAttribute(v0.quat.y, v1.quat.y, v2.quat.y).ToFloat32(),
+                 GetInterpolatedAttribute(v0.quat.z, v1.quat.z, v2.quat.z).ToFloat32()},
                 GetInterpolatedAttribute(v0.quat.w, v1.quat.w, v2.quat.w).ToFloat32(),
             };
 
             Math::Vec3<float> fragment_position{
                 GetInterpolatedAttribute(v0.view.x, v1.view.x, v2.view.x).ToFloat32(),
                 GetInterpolatedAttribute(v0.view.y, v1.view.y, v2.view.y).ToFloat32(),
-                GetInterpolatedAttribute(v0.view.z, v1.view.z, v2.view.z).ToFloat32()
-            };
+                GetInterpolatedAttribute(v0.view.z, v1.view.z, v2.view.z).ToFloat32()};
 
             Math::Vec2<float24> uv[3];
             uv[0].u() = GetInterpolatedAttribute(v0.tc0.u(), v1.tc0.u(), v2.tc0.u());
@@ -685,7 +722,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
             Math::Vec4<u8> primary_fragment_color;
             Math::Vec4<u8> secondary_fragment_color;
 
-            std::tie(primary_fragment_color, secondary_fragment_color) = ComputeFragmentsColors(normquat, fragment_position);
+            std::tie(primary_fragment_color, secondary_fragment_color) =
+                ComputeFragmentsColors(normquat, fragment_position);
 
             for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size();
                  ++tev_stage_index) {

From 6250f52e939c714ccb302003502ee78941c8221b Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Tue, 13 Jun 2017 12:36:45 -0500
Subject: [PATCH 10/27] SwRasterizer: Fixed a few conversion warnings and moved
 per-light values into the per-light loop.

---
 src/video_core/swrasterizer/rasterizer.cpp | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index 382b5927b..54af53bbd 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -143,18 +143,18 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
     // Use the normalized the quaternion when performing the rotation
     auto normal = Math::QuaternionRotate(normquat.Normalized(), surface_normal);
 
-    Math::Vec3<float> light_vector = {};
     Math::Vec4<float> diffuse_sum = {0.f, 0.f, 0.f, 1.f};
     Math::Vec4<float> specular_sum = {0.f, 0.f, 0.f, 1.f};
-    Math::Vec3<float> refl_value = {};
 
     for (unsigned light_index = 0; light_index <= lighting.max_light_index; ++light_index) {
         unsigned num = lighting.light_enable.GetNum(light_index);
         const auto& light_config = g_state.regs.lighting.light[num];
 
+        Math::Vec3<float> refl_value = {};
         Math::Vec3<float> position = {float16::FromRaw(light_config.x).ToFloat32(),
                                       float16::FromRaw(light_config.y).ToFloat32(),
                                       float16::FromRaw(light_config.z).ToFloat32()};
+        Math::Vec3<float> light_vector;
 
         if (light_config.config.directional)
             light_vector = position;
@@ -175,11 +175,12 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
         if (!lighting.IsDistAttenDisabled(num)) {
             auto distance = (-view - position).Length();
             float scale = Pica::float20::FromRaw(light_config.dist_atten_scale).ToFloat32();
-            float bias = Pica::float20::FromRaw(light_config.dist_atten_scale).ToFloat32();
+            float dist_aten_bias =
+                Pica::float20::FromRaw(light_config.dist_atten_scale).ToFloat32();
             size_t lut =
                 static_cast<size_t>(LightingRegs::LightingSampler::DistanceAttenuation) + num;
 
-            float sample_loc = scale * distance + bias;
+            float sample_loc = scale * distance + dist_aten_bias;
 
             u8 lutindex =
                 static_cast<u8>(MathUtil::Clamp(std::floor(sample_loc * 256.f), 0.0f, 255.0f));
@@ -238,7 +239,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
                 return {lutindex, delta};
             } else {
                 float flr = std::floor(result * 128.f);
-                s8 lutindex = static_cast<u8>(MathUtil::Clamp(flr, -128.0f, 127.0f));
+                s8 lutindex = static_cast<s8>(MathUtil::Clamp(flr, -128.0f, 127.0f));
                 float delta = result * 128.f - lutindex;
                 return {static_cast<u8>(lutindex), delta};
             }

From 37ac2b6657002e19d78cbc97841f8d3eee6ac5b8 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Tue, 13 Jun 2017 12:53:50 -0500
Subject: [PATCH 11/27] SwRasterizer/Lighting: Fixed a bug where the distance
 attenuation bias was being set to the dist atten scale.

---
 src/video_core/swrasterizer/rasterizer.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index 54af53bbd..48ed8ccbf 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -175,12 +175,11 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
         if (!lighting.IsDistAttenDisabled(num)) {
             auto distance = (-view - position).Length();
             float scale = Pica::float20::FromRaw(light_config.dist_atten_scale).ToFloat32();
-            float dist_aten_bias =
-                Pica::float20::FromRaw(light_config.dist_atten_scale).ToFloat32();
+            float bias = Pica::float20::FromRaw(light_config.dist_atten_bias).ToFloat32();
             size_t lut =
                 static_cast<size_t>(LightingRegs::LightingSampler::DistanceAttenuation) + num;
 
-            float sample_loc = scale * distance + dist_aten_bias;
+            float sample_loc = scale * distance + bias;
 
             u8 lutindex =
                 static_cast<u8>(MathUtil::Clamp(std::floor(sample_loc * 256.f), 0.0f, 255.0f));

From 7bc467e8725c6751eb44ea45ff2203af8692cda1 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Wed, 28 Jun 2017 12:34:16 -0500
Subject: [PATCH 12/27] SwRasterizer/Lighting: Do not use global state in
 LookupLightingLut.

---
 src/video_core/pica_state.h                |  2 +-
 src/video_core/swrasterizer/rasterizer.cpp | 33 ++++++++++++++--------
 2 files changed, 22 insertions(+), 13 deletions(-)

diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index 2d23d34e6..864a2c9e6 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -79,7 +79,7 @@ struct State {
         std::array<ColorDifferenceEntry, 256> color_diff_table;
     } proctex;
 
-    struct {
+    struct Lighting {
         union LutEntry {
             // Used for raw access
             u32 raw;
diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index 48ed8ccbf..b69f7b692 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -115,12 +115,15 @@ static std::tuple<float24, float24, PAddr> ConvertCubeCoord(float24 u, float24 v
     return std::make_tuple(x / z * half + half, y / z * half + half, addr);
 }
 
-float LookupLightingLut(size_t lut_index, u8 index, float delta) {
-    ASSERT_MSG(lut_index < g_state.lighting.luts.size(), "Out of range lut");
-    ASSERT_MSG(index < g_state.lighting.luts[0].size(), "Out of range index");
+static float LookupLightingLut(const Pica::State::Lighting& lighting, size_t lut_index, u8 index,
+                        float delta) {
+    ASSERT_MSG(lut_index < lighting.luts.size(), "Out of range lut");
+    ASSERT_MSG(index < lighting.luts[0].size(), "Out of range index");
 
-    float lut_value = g_state.lighting.luts[lut_index][index].ToFloat();
-    float lut_diff = g_state.lighting.luts[lut_index][index].DiffToFloat();
+    const auto& lut = lighting.luts[lut_index][index];
+
+    float lut_value = lut.ToFloat();
+    float lut_diff = lut.DiffToFloat();
 
     return lut_value + lut_diff * delta;
 }
@@ -184,7 +187,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
             u8 lutindex =
                 static_cast<u8>(MathUtil::Clamp(std::floor(sample_loc * 256.f), 0.0f, 255.0f));
             float delta = sample_loc * 256 - lutindex;
-            dist_atten = LookupLightingLut(lut, lutindex, delta);
+            dist_atten = LookupLightingLut(g_state.lighting, lut, lutindex, delta);
         }
 
         float clamp_highlights = 1.0f;
@@ -260,7 +263,8 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
 
             d0_lut_value =
                 scale *
-                LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Distribution0),
+                LookupLightingLut(g_state.lighting,
+                                  static_cast<size_t>(LightingRegs::LightingSampler::Distribution0),
                                   index, delta);
         }
 
@@ -280,7 +284,8 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
 
             refl_value.x =
                 scale *
-                LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectRed),
+                LookupLightingLut(g_state.lighting,
+                                  static_cast<size_t>(LightingRegs::LightingSampler::ReflectRed),
                                   index, delta);
         } else {
             refl_value.x = 1.0f;
@@ -300,7 +305,8 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
 
             refl_value.y =
                 scale *
-                LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectGreen),
+                LookupLightingLut(g_state.lighting,
+                                  static_cast<size_t>(LightingRegs::LightingSampler::ReflectGreen),
                                   index, delta);
         } else {
             refl_value.y = refl_value.x;
@@ -320,7 +326,8 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
 
             refl_value.z =
                 scale *
-                LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::ReflectBlue),
+                LookupLightingLut(g_state.lighting,
+                                  static_cast<size_t>(LightingRegs::LightingSampler::ReflectBlue),
                                   index, delta);
         } else {
             refl_value.z = refl_value.x;
@@ -341,7 +348,8 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
 
             d1_lut_value =
                 scale *
-                LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Distribution1),
+                LookupLightingLut(g_state.lighting,
+                                  static_cast<size_t>(LightingRegs::LightingSampler::Distribution1),
                                   index, delta);
         }
 
@@ -362,7 +370,8 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
 
             float lut_value =
                 scale *
-                LookupLightingLut(static_cast<size_t>(LightingRegs::LightingSampler::Fresnel),
+                LookupLightingLut(g_state.lighting,
+                                  static_cast<size_t>(LightingRegs::LightingSampler::Fresnel),
                                   index, delta);
 
             // Enabled for diffuse lighting alpha component

From b8229a768434ab9b47123359669761c05ecdd6b0 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Wed, 28 Jun 2017 12:35:35 -0500
Subject: [PATCH 13/27] SwRasterizer/Lighting: Do not use global registers
 state in ComputeFragmentsColors.

---
 src/video_core/swrasterizer/rasterizer.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index b69f7b692..d2d77e8b0 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -129,8 +129,8 @@ static float LookupLightingLut(const Pica::State::Lighting& lighting, size_t lut
 }
 
 std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
-    const Math::Quaternion<float>& normquat, const Math::Vec3<float>& view) {
-    const auto& lighting = g_state.regs.lighting;
+    const Pica::LightingRegs& lighting, const Math::Quaternion<float>& normquat,
+    const Math::Vec3<float>& view) {
 
     if (lighting.disable)
         return {Math::MakeVec<u8>(0, 0, 0, 0), Math::MakeVec<u8>(0, 0, 0, 0)};
@@ -732,7 +732,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
             Math::Vec4<u8> secondary_fragment_color;
 
             std::tie(primary_fragment_color, secondary_fragment_color) =
-                ComputeFragmentsColors(normquat, fragment_position);
+                ComputeFragmentsColors(g_state.regs.lighting, normquat, fragment_position);
 
             for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size();
                  ++tev_stage_index) {

From 7526af5e52ac1e24512faa1cd8f1a169407689fb Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Wed, 28 Jun 2017 12:37:14 -0500
Subject: [PATCH 14/27] SwRasterizer/Lighting: Move the lighting enable check
 outside the ComputeFragmentsColors function.

---
 src/video_core/swrasterizer/rasterizer.cpp | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index d2d77e8b0..b2d2b6ef2 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -132,9 +132,6 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
     const Pica::LightingRegs& lighting, const Math::Quaternion<float>& normquat,
     const Math::Vec3<float>& view) {
 
-    if (lighting.disable)
-        return {Math::MakeVec<u8>(0, 0, 0, 0), Math::MakeVec<u8>(0, 0, 0, 0)};
-
     // TODO(Subv): Bump mapping
     Math::Vec3<float> surface_normal = {0.0f, 0.0f, 1.0f};
 
@@ -728,11 +725,13 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
                 regs.texturing.tev_combiner_buffer_color.a,
             };
 
-            Math::Vec4<u8> primary_fragment_color;
-            Math::Vec4<u8> secondary_fragment_color;
+            Math::Vec4<u8> primary_fragment_color = {0, 0, 0, 0};
+            Math::Vec4<u8> secondary_fragment_color = {0, 0, 0, 0};
 
-            std::tie(primary_fragment_color, secondary_fragment_color) =
-                ComputeFragmentsColors(g_state.regs.lighting, normquat, fragment_position);
+            if (!g_state.regs.lighting.disable) {
+                std::tie(primary_fragment_color, secondary_fragment_color) =
+                    ComputeFragmentsColors(g_state.regs.lighting, normquat, fragment_position);
+            }
 
             for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size();
                  ++tev_stage_index) {

From 9906feefbd37ebfd658fecc47e960f23adc6b190 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Wed, 28 Jun 2017 12:43:00 -0500
Subject: [PATCH 15/27] SwRasterizer/Lighting: Move the clamp highlight
 calculation to the end of the per-light loop body.

---
 src/video_core/swrasterizer/rasterizer.cpp | 34 +++++++++++-----------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index b2d2b6ef2..2c7a1a815 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -163,14 +163,6 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
 
         light_vector.Normalize();
 
-        auto LV_N = Math::Dot(light_vector, normal);
-        auto dot_product = LV_N;
-
-        if (light_config.config.two_sided_diffuse)
-            dot_product = std::abs(dot_product);
-        else
-            dot_product = std::max(dot_product, 0.0f);
-
         float dist_atten = 1.0f;
         if (!lighting.IsDistAttenDisabled(num)) {
             auto distance = (-view - position).Length();
@@ -187,15 +179,6 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
             dist_atten = LookupLightingLut(g_state.lighting, lut, lutindex, delta);
         }
 
-        float clamp_highlights = 1.0f;
-
-        if (lighting.config0.clamp_highlights) {
-            if (LV_N <= 0.f)
-                clamp_highlights = 0.f;
-            else
-                clamp_highlights = 1.f;
-        }
-
         auto GetLutIndex = [&](unsigned num, LightingRegs::LightingLutInput input,
                                bool abs) -> std::tuple<u8, float> {
 
@@ -386,6 +369,23 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
             }
         }
 
+        auto dot_product = Math::Dot(light_vector, normal);
+
+        // Calculate clamp highlights before applying the two-sided diffuse configuration to the dot
+        // product.
+        float clamp_highlights = 1.0f;
+        if (lighting.config0.clamp_highlights) {
+            if (dot_product <= 0.f)
+                clamp_highlights = 0.f;
+            else
+                clamp_highlights = 1.f;
+        }
+
+        if (light_config.config.two_sided_diffuse)
+            dot_product = std::abs(dot_product);
+        else
+            dot_product = std::max(dot_product, 0.0f);
+
         auto diffuse =
             light_config.diffuse.ToVec3f() * dot_product + light_config.ambient.ToVec3f();
         diffuse_sum += Math::MakeVec(diffuse * dist_atten, 0.0f);

From f3660ba9dd13f342c591aaa9901e94b6caee8d9a Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Tue, 11 Jul 2017 19:51:29 +0300
Subject: [PATCH 16/27] vector_math: remove broken SFINAE stuff

this was originally added to eliminate warnings on MSVC, but it doesn't work for custom types.
---
 src/common/vector_math.h | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index d0fe0e405..49ae87f6d 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -31,7 +31,6 @@
 #pragma once
 
 #include <cmath>
-#include <type_traits>
 
 namespace Math {
 
@@ -90,7 +89,7 @@ public:
         x -= other.x;
         y -= other.y;
     }
-    template <typename Q = T, class = typename std::enable_if<std::is_signed<Q>::value>::type>
+
     Vec2<decltype(-T{})> operator-() const {
         return MakeVec(-x, -y);
     }
@@ -247,7 +246,7 @@ public:
         y -= other.y;
         z -= other.z;
     }
-    template <typename Q = T, class = typename std::enable_if<std::is_signed<Q>::value>::type>
+
     Vec3<decltype(-T{})> operator-() const {
         return MakeVec(-x, -y, -z);
     }

From efc655aec00d43d53c41b55d9a94d17ce81e5942 Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Tue, 11 Jul 2017 20:06:26 +0300
Subject: [PATCH 17/27] SwRasterizer/Lighting: pass lighting state as parameter

---
 src/video_core/swrasterizer/rasterizer.cpp | 26 +++++++++++-----------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index 2c7a1a815..b108a0f86 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -116,7 +116,7 @@ static std::tuple<float24, float24, PAddr> ConvertCubeCoord(float24 u, float24 v
 }
 
 static float LookupLightingLut(const Pica::State::Lighting& lighting, size_t lut_index, u8 index,
-                        float delta) {
+                               float delta) {
     ASSERT_MSG(lut_index < lighting.luts.size(), "Out of range lut");
     ASSERT_MSG(index < lighting.luts[0].size(), "Out of range index");
 
@@ -129,8 +129,8 @@ 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 Math::Quaternion<float>& normquat,
-    const Math::Vec3<float>& view) {
+    const Pica::LightingRegs& lighting, const Pica::State::Lighting& lighting_state,
+    const Math::Quaternion<float>& normquat, const Math::Vec3<float>& view) {
 
     // TODO(Subv): Bump mapping
     Math::Vec3<float> surface_normal = {0.0f, 0.0f, 1.0f};
@@ -148,7 +148,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
 
     for (unsigned light_index = 0; light_index <= lighting.max_light_index; ++light_index) {
         unsigned num = lighting.light_enable.GetNum(light_index);
-        const auto& light_config = g_state.regs.lighting.light[num];
+        const auto& light_config = lighting.light[num];
 
         Math::Vec3<float> refl_value = {};
         Math::Vec3<float> position = {float16::FromRaw(light_config.x).ToFloat32(),
@@ -176,7 +176,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
             u8 lutindex =
                 static_cast<u8>(MathUtil::Clamp(std::floor(sample_loc * 256.f), 0.0f, 255.0f));
             float delta = sample_loc * 256 - lutindex;
-            dist_atten = LookupLightingLut(g_state.lighting, lut, lutindex, delta);
+            dist_atten = LookupLightingLut(lighting_state, lut, lutindex, delta);
         }
 
         auto GetLutIndex = [&](unsigned num, LightingRegs::LightingLutInput input,
@@ -243,7 +243,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
 
             d0_lut_value =
                 scale *
-                LookupLightingLut(g_state.lighting,
+                LookupLightingLut(lighting_state,
                                   static_cast<size_t>(LightingRegs::LightingSampler::Distribution0),
                                   index, delta);
         }
@@ -264,7 +264,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
 
             refl_value.x =
                 scale *
-                LookupLightingLut(g_state.lighting,
+                LookupLightingLut(lighting_state,
                                   static_cast<size_t>(LightingRegs::LightingSampler::ReflectRed),
                                   index, delta);
         } else {
@@ -285,7 +285,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
 
             refl_value.y =
                 scale *
-                LookupLightingLut(g_state.lighting,
+                LookupLightingLut(lighting_state,
                                   static_cast<size_t>(LightingRegs::LightingSampler::ReflectGreen),
                                   index, delta);
         } else {
@@ -306,7 +306,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
 
             refl_value.z =
                 scale *
-                LookupLightingLut(g_state.lighting,
+                LookupLightingLut(lighting_state,
                                   static_cast<size_t>(LightingRegs::LightingSampler::ReflectBlue),
                                   index, delta);
         } else {
@@ -328,7 +328,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
 
             d1_lut_value =
                 scale *
-                LookupLightingLut(g_state.lighting,
+                LookupLightingLut(lighting_state,
                                   static_cast<size_t>(LightingRegs::LightingSampler::Distribution1),
                                   index, delta);
         }
@@ -350,7 +350,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
 
             float lut_value =
                 scale *
-                LookupLightingLut(g_state.lighting,
+                LookupLightingLut(lighting_state,
                                   static_cast<size_t>(LightingRegs::LightingSampler::Fresnel),
                                   index, delta);
 
@@ -729,8 +729,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
             Math::Vec4<u8> secondary_fragment_color = {0, 0, 0, 0};
 
             if (!g_state.regs.lighting.disable) {
-                std::tie(primary_fragment_color, secondary_fragment_color) =
-                    ComputeFragmentsColors(g_state.regs.lighting, normquat, fragment_position);
+                std::tie(primary_fragment_color, secondary_fragment_color) = ComputeFragmentsColors(
+                    g_state.regs.lighting, g_state.lighting, normquat, fragment_position);
             }
 
             for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size();

From fe44e843fe1e300491d3bcd9072948407a86e7e1 Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Tue, 11 Jul 2017 20:08:56 +0300
Subject: [PATCH 18/27] vector_math: remove dead template parameter

---
 src/common/vector_math.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index 49ae87f6d..6e2a5ad60 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -461,7 +461,7 @@ public:
         z -= other.z;
         w -= other.w;
     }
-    template <typename Q = T>
+
     Vec4<decltype(-T{})> operator-() const {
         return MakeVec(-x, -y, -z, -w);
     }

From f13cf506e0b0e42e6c9b00b163aaabc3b63fb7ea Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Tue, 11 Jul 2017 20:15:23 +0300
Subject: [PATCH 19/27] SwRasterizer: only interpolate quat and view when
 lighting is enabled

---
 src/video_core/swrasterizer/rasterizer.cpp | 28 +++++++++++-----------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index b108a0f86..5844c401c 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -599,18 +599,6 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
                     255),
             };
 
-            Math::Quaternion<float> normquat{
-                {GetInterpolatedAttribute(v0.quat.x, v1.quat.x, v2.quat.x).ToFloat32(),
-                 GetInterpolatedAttribute(v0.quat.y, v1.quat.y, v2.quat.y).ToFloat32(),
-                 GetInterpolatedAttribute(v0.quat.z, v1.quat.z, v2.quat.z).ToFloat32()},
-                GetInterpolatedAttribute(v0.quat.w, v1.quat.w, v2.quat.w).ToFloat32(),
-            };
-
-            Math::Vec3<float> fragment_position{
-                GetInterpolatedAttribute(v0.view.x, v1.view.x, v2.view.x).ToFloat32(),
-                GetInterpolatedAttribute(v0.view.y, v1.view.y, v2.view.y).ToFloat32(),
-                GetInterpolatedAttribute(v0.view.z, v1.view.z, v2.view.z).ToFloat32()};
-
             Math::Vec2<float24> uv[3];
             uv[0].u() = GetInterpolatedAttribute(v0.tc0.u(), v1.tc0.u(), v2.tc0.u());
             uv[0].v() = GetInterpolatedAttribute(v0.tc0.v(), v1.tc0.v(), v2.tc0.v());
@@ -729,8 +717,20 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
             Math::Vec4<u8> secondary_fragment_color = {0, 0, 0, 0};
 
             if (!g_state.regs.lighting.disable) {
-                std::tie(primary_fragment_color, secondary_fragment_color) = ComputeFragmentsColors(
-                    g_state.regs.lighting, g_state.lighting, normquat, fragment_position);
+                Math::Quaternion<float> normquat{
+                    {GetInterpolatedAttribute(v0.quat.x, v1.quat.x, v2.quat.x).ToFloat32(),
+                     GetInterpolatedAttribute(v0.quat.y, v1.quat.y, v2.quat.y).ToFloat32(),
+                     GetInterpolatedAttribute(v0.quat.z, v1.quat.z, v2.quat.z).ToFloat32()},
+                    GetInterpolatedAttribute(v0.quat.w, v1.quat.w, v2.quat.w).ToFloat32(),
+                };
+
+                Math::Vec3<float> view{
+                    GetInterpolatedAttribute(v0.view.x, v1.view.x, v2.view.x).ToFloat32(),
+                    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);
             }
 
             for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size();

From c6d1472513394cc55b5d5a852d5f76b5e9a51f2b Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Tue, 11 Jul 2017 21:36:19 +0300
Subject: [PATCH 20/27] SwRasterizer/Lighting: refactor GetLutValue into a
 function.

merging similar pattern. Also makes the code more similar to the gl one
---
 src/video_core/swrasterizer/rasterizer.cpp | 110 +++++----------------
 1 file changed, 27 insertions(+), 83 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index 5844c401c..53c3bb585 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -179,9 +179,9 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
             dist_atten = LookupLightingLut(lighting_state, lut, lutindex, delta);
         }
 
-        auto GetLutIndex = [&](unsigned num, LightingRegs::LightingLutInput input,
-                               bool abs) -> std::tuple<u8, float> {
-
+        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;
@@ -209,6 +209,9 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
                 result = 0.f;
             }
 
+            u8 index;
+            float delta;
+
             if (abs) {
                 if (light_config.config.two_sided_diffuse)
                     result = std::abs(result);
@@ -216,15 +219,18 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
                     result = std::max(result, 0.0f);
 
                 float flr = std::floor(result * 256.f);
-                u8 lutindex = static_cast<u8>(MathUtil::Clamp(flr, 0.0f, 255.0f));
-                float delta = result * 256 - lutindex;
-                return {lutindex, delta};
+                index = static_cast<u8>(MathUtil::Clamp(flr, 0.0f, 255.0f));
+                delta = result * 256 - index;
             } else {
                 float flr = std::floor(result * 128.f);
-                s8 lutindex = static_cast<s8>(MathUtil::Clamp(flr, -128.0f, 127.0f));
-                float delta = result * 128.f - lutindex;
-                return {static_cast<u8>(lutindex), delta};
+                s8 signed_index = static_cast<s8>(MathUtil::Clamp(flr, -128.0f, 127.0f));
+                delta = result * 128.f - signed_index;
+                index = static_cast<u8>(signed_index);
             }
+
+            float scale = lighting.lut_scale.GetScale(scale_enum);
+            return scale *
+                   LookupLightingLut(lighting_state, static_cast<size_t>(sampler), index, delta);
         };
 
         // Specular 0 component
@@ -232,20 +238,9 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
         if (lighting.config1.disable_lut_d0 == 0 &&
             LightingRegs::IsLightingSamplerSupported(
                 lighting.config0.config, LightingRegs::LightingSampler::Distribution0)) {
-
-            // Lookup specular "distribution 0" LUT value
-            u8 index;
-            float delta;
-            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.d0.Value(),
-                                                 lighting.abs_lut_input.disable_d0 == 0);
-
-            float scale = lighting.lut_scale.GetScale(lighting.lut_scale.d0);
-
             d0_lut_value =
-                scale *
-                LookupLightingLut(lighting_state,
-                                  static_cast<size_t>(LightingRegs::LightingSampler::Distribution0),
-                                  index, delta);
+                GetLutValue(lighting.lut_input.d0, lighting.abs_lut_input.disable_d0 == 0,
+                            lighting.lut_scale.d0, LightingRegs::LightingSampler::Distribution0);
         }
 
         Math::Vec3<float> specular_0 = d0_lut_value * light_config.specular_0.ToVec3f();
@@ -254,19 +249,9 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
         if (lighting.config1.disable_lut_rr == 0 &&
             LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
                                                      LightingRegs::LightingSampler::ReflectRed)) {
-
-            u8 index;
-            float delta;
-            std::tie(index, delta) =
-                GetLutIndex(num, lighting.lut_input.rr, lighting.abs_lut_input.disable_rr == 0);
-
-            float scale = lighting.lut_scale.GetScale(lighting.lut_scale.rr);
-
             refl_value.x =
-                scale *
-                LookupLightingLut(lighting_state,
-                                  static_cast<size_t>(LightingRegs::LightingSampler::ReflectRed),
-                                  index, delta);
+                GetLutValue(lighting.lut_input.rr, lighting.abs_lut_input.disable_rr == 0,
+                            lighting.lut_scale.rr, LightingRegs::LightingSampler::ReflectRed);
         } else {
             refl_value.x = 1.0f;
         }
@@ -275,19 +260,9 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
         if (lighting.config1.disable_lut_rg == 0 &&
             LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
                                                      LightingRegs::LightingSampler::ReflectGreen)) {
-
-            u8 index;
-            float delta;
-            std::tie(index, delta) =
-                GetLutIndex(num, lighting.lut_input.rg, lighting.abs_lut_input.disable_rg == 0);
-
-            float scale = lighting.lut_scale.GetScale(lighting.lut_scale.rg);
-
             refl_value.y =
-                scale *
-                LookupLightingLut(lighting_state,
-                                  static_cast<size_t>(LightingRegs::LightingSampler::ReflectGreen),
-                                  index, delta);
+                GetLutValue(lighting.lut_input.rg, lighting.abs_lut_input.disable_rg == 0,
+                            lighting.lut_scale.rg, LightingRegs::LightingSampler::ReflectGreen);
         } else {
             refl_value.y = refl_value.x;
         }
@@ -296,19 +271,9 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
         if (lighting.config1.disable_lut_rb == 0 &&
             LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
                                                      LightingRegs::LightingSampler::ReflectBlue)) {
-
-            u8 index;
-            float delta;
-            std::tie(index, delta) =
-                GetLutIndex(num, lighting.lut_input.rb, lighting.abs_lut_input.disable_rb == 0);
-
-            float scale = lighting.lut_scale.GetScale(lighting.lut_scale.rb);
-
             refl_value.z =
-                scale *
-                LookupLightingLut(lighting_state,
-                                  static_cast<size_t>(LightingRegs::LightingSampler::ReflectBlue),
-                                  index, delta);
+                GetLutValue(lighting.lut_input.rb, lighting.abs_lut_input.disable_rb == 0,
+                            lighting.lut_scale.rb, LightingRegs::LightingSampler::ReflectBlue);
         } else {
             refl_value.z = refl_value.x;
         }
@@ -317,20 +282,9 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
         if (lighting.config1.disable_lut_d1 == 0 &&
             LightingRegs::IsLightingSamplerSupported(
                 lighting.config0.config, LightingRegs::LightingSampler::Distribution1)) {
-
-            // Lookup specular "distribution 1" LUT value
-            u8 index;
-            float delta;
-            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.d1.Value(),
-                                                 lighting.abs_lut_input.disable_d1 == 0);
-
-            float scale = lighting.lut_scale.GetScale(lighting.lut_scale.d1);
-
             d1_lut_value =
-                scale *
-                LookupLightingLut(lighting_state,
-                                  static_cast<size_t>(LightingRegs::LightingSampler::Distribution1),
-                                  index, delta);
+                GetLutValue(lighting.lut_input.d1, lighting.abs_lut_input.disable_d1 == 0,
+                            lighting.lut_scale.d1, LightingRegs::LightingSampler::Distribution1);
         }
 
         Math::Vec3<float> specular_1 =
@@ -340,19 +294,9 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
             LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
                                                      LightingRegs::LightingSampler::Fresnel)) {
 
-            // Lookup fresnel LUT value
-            u8 index;
-            float delta;
-            std::tie(index, delta) = GetLutIndex(num, lighting.lut_input.fr.Value(),
-                                                 lighting.abs_lut_input.disable_fr == 0);
-
-            float scale = lighting.lut_scale.GetScale(lighting.lut_scale.fr);
-
             float lut_value =
-                scale *
-                LookupLightingLut(lighting_state,
-                                  static_cast<size_t>(LightingRegs::LightingSampler::Fresnel),
-                                  index, delta);
+                GetLutValue(lighting.lut_input.fr, lighting.abs_lut_input.disable_fr == 0,
+                            lighting.lut_scale.fr, LightingRegs::LightingSampler::Fresnel);
 
             // Enabled for diffuse lighting alpha component
             if (lighting.config0.fresnel_selector ==

From e415558a4fc471bc3ac2d22dd8052aeb63769c6e Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Tue, 11 Jul 2017 21:47:55 +0300
Subject: [PATCH 21/27] SwRasterizer/Lighting: get rid of nested return

---
 src/video_core/swrasterizer/rasterizer.cpp | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index 53c3bb585..e46790f85 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -340,16 +340,17 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
 
     diffuse_sum += Math::MakeVec(lighting.global_ambient.ToVec3f(), 0.0f);
 
-    return {Math::MakeVec<float>(MathUtil::Clamp(diffuse_sum.x, 0.0f, 1.0f) * 255,
-                                 MathUtil::Clamp(diffuse_sum.y, 0.0f, 1.0f) * 255,
-                                 MathUtil::Clamp(diffuse_sum.z, 0.0f, 1.0f) * 255,
-                                 MathUtil::Clamp(diffuse_sum.w, 0.0f, 1.0f) * 255)
-                .Cast<u8>(),
-            Math::MakeVec<float>(MathUtil::Clamp(specular_sum.x, 0.0f, 1.0f) * 255,
-                                 MathUtil::Clamp(specular_sum.y, 0.0f, 1.0f) * 255,
-                                 MathUtil::Clamp(specular_sum.z, 0.0f, 1.0f) * 255,
-                                 MathUtil::Clamp(specular_sum.w, 0.0f, 1.0f) * 255)
-                .Cast<u8>()};
+    auto diffuse = Math::MakeVec<float>(MathUtil::Clamp(diffuse_sum.x, 0.0f, 1.0f) * 255,
+                                        MathUtil::Clamp(diffuse_sum.y, 0.0f, 1.0f) * 255,
+                                        MathUtil::Clamp(diffuse_sum.z, 0.0f, 1.0f) * 255,
+                                        MathUtil::Clamp(diffuse_sum.w, 0.0f, 1.0f) * 255)
+                       .Cast<u8>();
+    auto specular = Math::MakeVec<float>(MathUtil::Clamp(specular_sum.x, 0.0f, 1.0f) * 255,
+                                         MathUtil::Clamp(specular_sum.y, 0.0f, 1.0f) * 255,
+                                         MathUtil::Clamp(specular_sum.z, 0.0f, 1.0f) * 255,
+                                         MathUtil::Clamp(specular_sum.w, 0.0f, 1.0f) * 255)
+                        .Cast<u8>();
+    return {diffuse, specular};
 }
 
 MICROPROFILE_DEFINE(GPU_Rasterization, "GPU", "Rasterization", MP_RGB(50, 50, 240));

From 56e5425e593e29aecf255c441791f2e24512f418 Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Tue, 11 Jul 2017 22:07:19 +0300
Subject: [PATCH 22/27] SwRasterizer/Lighting: unify float suffix

---
 src/video_core/swrasterizer/rasterizer.cpp | 24 ++++++++++++----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index e46790f85..c83680629 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -143,8 +143,8 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
     // Use the normalized the quaternion when performing the rotation
     auto normal = Math::QuaternionRotate(normquat.Normalized(), surface_normal);
 
-    Math::Vec4<float> diffuse_sum = {0.f, 0.f, 0.f, 1.f};
-    Math::Vec4<float> specular_sum = {0.f, 0.f, 0.f, 1.f};
+    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};
 
     for (unsigned light_index = 0; light_index <= lighting.max_light_index; ++light_index) {
         unsigned num = lighting.light_enable.GetNum(light_index);
@@ -174,7 +174,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
             float sample_loc = scale * distance + bias;
 
             u8 lutindex =
-                static_cast<u8>(MathUtil::Clamp(std::floor(sample_loc * 256.f), 0.0f, 255.0f));
+                static_cast<u8>(MathUtil::Clamp(std::floor(sample_loc * 256.0f), 0.0f, 255.0f));
             float delta = sample_loc * 256 - lutindex;
             dist_atten = LookupLightingLut(lighting_state, lut, lutindex, delta);
         }
@@ -206,7 +206,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
             default:
                 LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %u\n", static_cast<u32>(input));
                 UNIMPLEMENTED();
-                result = 0.f;
+                result = 0.0f;
             }
 
             u8 index;
@@ -218,13 +218,13 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
                 else
                     result = std::max(result, 0.0f);
 
-                float flr = std::floor(result * 256.f);
+                float flr = std::floor(result * 256.0f);
                 index = static_cast<u8>(MathUtil::Clamp(flr, 0.0f, 255.0f));
                 delta = result * 256 - index;
             } else {
-                float flr = std::floor(result * 128.f);
+                float flr = std::floor(result * 128.0f);
                 s8 signed_index = static_cast<s8>(MathUtil::Clamp(flr, -128.0f, 127.0f));
-                delta = result * 128.f - signed_index;
+                delta = result * 128.0f - signed_index;
                 index = static_cast<u8>(signed_index);
             }
 
@@ -278,6 +278,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
             refl_value.z = refl_value.x;
         }
 
+        // Specular 1 component
         float d1_lut_value = 1.0f;
         if (lighting.config1.disable_lut_d1 == 0 &&
             LightingRegs::IsLightingSamplerSupported(
@@ -290,6 +291,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
         Math::Vec3<float> specular_1 =
             d1_lut_value * refl_value * light_config.specular_1.ToVec3f();
 
+        // Fresnel
         if (lighting.config1.disable_lut_fr == 0 &&
             LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
                                                      LightingRegs::LightingSampler::Fresnel)) {
@@ -319,10 +321,10 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
         // product.
         float clamp_highlights = 1.0f;
         if (lighting.config0.clamp_highlights) {
-            if (dot_product <= 0.f)
-                clamp_highlights = 0.f;
+            if (dot_product <= 0.0f)
+                clamp_highlights = 0.0f;
             else
-                clamp_highlights = 1.f;
+                clamp_highlights = 1.0f;
         }
 
         if (light_config.config.two_sided_diffuse)
@@ -335,7 +337,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
         diffuse_sum += Math::MakeVec(diffuse * dist_atten, 0.0f);
 
         specular_sum +=
-            Math::MakeVec((specular_0 + specular_1) * clamp_highlights * dist_atten, 0.f);
+            Math::MakeVec((specular_0 + specular_1) * clamp_highlights * dist_atten, 0.0f);
     }
 
     diffuse_sum += Math::MakeVec(lighting.global_ambient.ToVec3f(), 0.0f);

From 4feff63ffaec4d62d5bdfc85968cc99298907767 Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Tue, 11 Jul 2017 22:19:00 +0300
Subject: [PATCH 23/27] SwRasterizer/Lighting: dist atten lut input need to be
 clamp

---
 src/video_core/swrasterizer/rasterizer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index c83680629..37d1313cf 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -171,7 +171,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
             size_t lut =
                 static_cast<size_t>(LightingRegs::LightingSampler::DistanceAttenuation) + num;
 
-            float sample_loc = scale * distance + bias;
+            float sample_loc = MathUtil::Clamp(scale * distance + bias, 0.0f, 1.0f);
 
             u8 lutindex =
                 static_cast<u8>(MathUtil::Clamp(std::floor(sample_loc * 256.0f), 0.0f, 255.0f));

From c59ed47608367de8cd5e4e6d58da02dee30810a9 Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Wed, 2 Aug 2017 22:05:53 +0300
Subject: [PATCH 24/27] SwRasterizer/Lighting: move quaternion normalization to
 the caller

---
 src/video_core/swrasterizer/rasterizer.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index 37d1313cf..80ecf72ec 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -141,7 +141,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
     }
 
     // Use the normalized the quaternion when performing the rotation
-    auto normal = Math::QuaternionRotate(normquat.Normalized(), surface_normal);
+    auto normal = Math::QuaternionRotate(normquat, surface_normal);
 
     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};
@@ -664,12 +664,12 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
             Math::Vec4<u8> secondary_fragment_color = {0, 0, 0, 0};
 
             if (!g_state.regs.lighting.disable) {
-                Math::Quaternion<float> normquat{
+                Math::Quaternion<float> normquat = Math::Quaternion<float>{
                     {GetInterpolatedAttribute(v0.quat.x, v1.quat.x, v2.quat.x).ToFloat32(),
                      GetInterpolatedAttribute(v0.quat.y, v1.quat.y, v2.quat.y).ToFloat32(),
                      GetInterpolatedAttribute(v0.quat.z, v1.quat.z, v2.quat.z).ToFloat32()},
                     GetInterpolatedAttribute(v0.quat.w, v1.quat.w, v2.quat.w).ToFloat32(),
-                };
+                }.Normalized();
 
                 Math::Vec3<float> view{
                     GetInterpolatedAttribute(v0.view.x, v1.view.x, v2.view.x).ToFloat32(),

From 48b410587116c92339d936ed3b1fd00aba38d6b5 Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Wed, 2 Aug 2017 22:07:15 +0300
Subject: [PATCH 25/27] SwRasterizer/Lighting: reduce confusion

---
 src/video_core/swrasterizer/rasterizer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index 80ecf72ec..aee630954 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -118,7 +118,7 @@ static std::tuple<float24, float24, PAddr> ConvertCubeCoord(float24 u, float24 v
 static float LookupLightingLut(const Pica::State::Lighting& lighting, size_t lut_index, u8 index,
                                float delta) {
     ASSERT_MSG(lut_index < lighting.luts.size(), "Out of range lut");
-    ASSERT_MSG(index < lighting.luts[0].size(), "Out of range index");
+    ASSERT_MSG(index < lighting.luts[lut_index].size(), "Out of range index");
 
     const auto& lut = lighting.luts[lut_index][index];
 

From eda28266fb1f0eb96a2096cadb41b62db3dc2d2e Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Wed, 2 Aug 2017 22:20:40 +0300
Subject: [PATCH 26/27] SwRasterizer/Lighting: move to its own file

---
 src/video_core/CMakeLists.txt                 |   2 +
 .../swrasterizer/fragment_lighting.cpp        | 250 ++++++++++++++++++
 .../swrasterizer/fragment_lighting.h          |  18 ++
 src/video_core/swrasterizer/rasterizer.cpp    | 241 +----------------
 4 files changed, 271 insertions(+), 240 deletions(-)
 create mode 100644 src/video_core/swrasterizer/fragment_lighting.cpp
 create mode 100644 src/video_core/swrasterizer/fragment_lighting.h

diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 0961a3251..b2280f2ef 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -14,6 +14,7 @@ set(SRCS
             shader/shader.cpp
             shader/shader_interpreter.cpp
             swrasterizer/clipper.cpp
+            swrasterizer/fragment_lighting.cpp
             swrasterizer/framebuffer.cpp
             swrasterizer/proctex.cpp
             swrasterizer/rasterizer.cpp
@@ -54,6 +55,7 @@ set(HEADERS
             shader/shader.h
             shader/shader_interpreter.h
             swrasterizer/clipper.h
+            swrasterizer/fragment_lighting.h
             swrasterizer/framebuffer.h
             swrasterizer/proctex.h
             swrasterizer/rasterizer.h
diff --git a/src/video_core/swrasterizer/fragment_lighting.cpp b/src/video_core/swrasterizer/fragment_lighting.cpp
new file mode 100644
index 000000000..45a86b5cd
--- /dev/null
+++ b/src/video_core/swrasterizer/fragment_lighting.cpp
@@ -0,0 +1,250 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/math_util.h"
+#include "video_core/swrasterizer/fragment_lighting.h"
+
+namespace Pica {
+
+static float LookupLightingLut(const Pica::State::Lighting& lighting, size_t lut_index, u8 index,
+                               float delta) {
+    ASSERT_MSG(lut_index < lighting.luts.size(), "Out of range lut");
+    ASSERT_MSG(index < lighting.luts[lut_index].size(), "Out of range index");
+
+    const auto& lut = lighting.luts[lut_index][index];
+
+    float lut_value = lut.ToFloat();
+    float lut_diff = lut.DiffToFloat();
+
+    return lut_value + lut_diff * delta;
+}
+
+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) {
+
+    // TODO(Subv): Bump mapping
+    Math::Vec3<float> surface_normal = {0.0f, 0.0f, 1.0f};
+
+    if (lighting.config0.bump_mode != LightingRegs::LightingBumpMode::None) {
+        LOG_CRITICAL(HW_GPU, "unimplemented bump mapping");
+        UNIMPLEMENTED();
+    }
+
+    // Use the normalized the quaternion when performing the rotation
+    auto normal = Math::QuaternionRotate(normquat, surface_normal);
+
+    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};
+
+    for (unsigned light_index = 0; light_index <= lighting.max_light_index; ++light_index) {
+        unsigned num = lighting.light_enable.GetNum(light_index);
+        const auto& light_config = lighting.light[num];
+
+        Math::Vec3<float> refl_value = {};
+        Math::Vec3<float> position = {float16::FromRaw(light_config.x).ToFloat32(),
+                                      float16::FromRaw(light_config.y).ToFloat32(),
+                                      float16::FromRaw(light_config.z).ToFloat32()};
+        Math::Vec3<float> light_vector;
+
+        if (light_config.config.directional)
+            light_vector = position;
+        else
+            light_vector = position + view;
+
+        light_vector.Normalize();
+
+        float dist_atten = 1.0f;
+        if (!lighting.IsDistAttenDisabled(num)) {
+            auto distance = (-view - position).Length();
+            float scale = Pica::float20::FromRaw(light_config.dist_atten_scale).ToFloat32();
+            float bias = Pica::float20::FromRaw(light_config.dist_atten_bias).ToFloat32();
+            size_t lut =
+                static_cast<size_t>(LightingRegs::LightingSampler::DistanceAttenuation) + num;
+
+            float sample_loc = MathUtil::Clamp(scale * distance + bias, 0.0f, 1.0f);
+
+            u8 lutindex =
+                static_cast<u8>(MathUtil::Clamp(std::floor(sample_loc * 256.0f), 0.0f, 255.0f));
+            float delta = sample_loc * 256 - lutindex;
+            dist_atten = LookupLightingLut(lighting_state, lut, lutindex, delta);
+        }
+
+        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);
+                break;
+
+            case LightingRegs::LightingLutInput::VH:
+                result = Math::Dot(norm_view, half_angle);
+                break;
+
+            case LightingRegs::LightingLutInput::NV:
+                result = Math::Dot(normal, norm_view);
+                break;
+
+            case LightingRegs::LightingLutInput::LN:
+                result = Math::Dot(light_vector, normal);
+                break;
+
+            default:
+                LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %u\n", static_cast<u32>(input));
+                UNIMPLEMENTED();
+                result = 0.0f;
+            }
+
+            u8 index;
+            float delta;
+
+            if (abs) {
+                if (light_config.config.two_sided_diffuse)
+                    result = std::abs(result);
+                else
+                    result = std::max(result, 0.0f);
+
+                float flr = std::floor(result * 256.0f);
+                index = static_cast<u8>(MathUtil::Clamp(flr, 0.0f, 255.0f));
+                delta = result * 256 - index;
+            } else {
+                float flr = std::floor(result * 128.0f);
+                s8 signed_index = static_cast<s8>(MathUtil::Clamp(flr, -128.0f, 127.0f));
+                delta = result * 128.0f - signed_index;
+                index = static_cast<u8>(signed_index);
+            }
+
+            float scale = lighting.lut_scale.GetScale(scale_enum);
+            return scale *
+                   LookupLightingLut(lighting_state, static_cast<size_t>(sampler), index, delta);
+        };
+
+        // Specular 0 component
+        float d0_lut_value = 1.0f;
+        if (lighting.config1.disable_lut_d0 == 0 &&
+            LightingRegs::IsLightingSamplerSupported(
+                lighting.config0.config, LightingRegs::LightingSampler::Distribution0)) {
+            d0_lut_value =
+                GetLutValue(lighting.lut_input.d0, lighting.abs_lut_input.disable_d0 == 0,
+                            lighting.lut_scale.d0, LightingRegs::LightingSampler::Distribution0);
+        }
+
+        Math::Vec3<float> specular_0 = d0_lut_value * light_config.specular_0.ToVec3f();
+
+        // If enabled, lookup ReflectRed value, otherwise, 1.0 is used
+        if (lighting.config1.disable_lut_rr == 0 &&
+            LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
+                                                     LightingRegs::LightingSampler::ReflectRed)) {
+            refl_value.x =
+                GetLutValue(lighting.lut_input.rr, lighting.abs_lut_input.disable_rr == 0,
+                            lighting.lut_scale.rr, LightingRegs::LightingSampler::ReflectRed);
+        } else {
+            refl_value.x = 1.0f;
+        }
+
+        // If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used
+        if (lighting.config1.disable_lut_rg == 0 &&
+            LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
+                                                     LightingRegs::LightingSampler::ReflectGreen)) {
+            refl_value.y =
+                GetLutValue(lighting.lut_input.rg, lighting.abs_lut_input.disable_rg == 0,
+                            lighting.lut_scale.rg, LightingRegs::LightingSampler::ReflectGreen);
+        } else {
+            refl_value.y = refl_value.x;
+        }
+
+        // If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used
+        if (lighting.config1.disable_lut_rb == 0 &&
+            LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
+                                                     LightingRegs::LightingSampler::ReflectBlue)) {
+            refl_value.z =
+                GetLutValue(lighting.lut_input.rb, lighting.abs_lut_input.disable_rb == 0,
+                            lighting.lut_scale.rb, LightingRegs::LightingSampler::ReflectBlue);
+        } else {
+            refl_value.z = refl_value.x;
+        }
+
+        // Specular 1 component
+        float d1_lut_value = 1.0f;
+        if (lighting.config1.disable_lut_d1 == 0 &&
+            LightingRegs::IsLightingSamplerSupported(
+                lighting.config0.config, LightingRegs::LightingSampler::Distribution1)) {
+            d1_lut_value =
+                GetLutValue(lighting.lut_input.d1, lighting.abs_lut_input.disable_d1 == 0,
+                            lighting.lut_scale.d1, LightingRegs::LightingSampler::Distribution1);
+        }
+
+        Math::Vec3<float> specular_1 =
+            d1_lut_value * refl_value * light_config.specular_1.ToVec3f();
+
+        // Fresnel
+        if (lighting.config1.disable_lut_fr == 0 &&
+            LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
+                                                     LightingRegs::LightingSampler::Fresnel)) {
+
+            float lut_value =
+                GetLutValue(lighting.lut_input.fr, lighting.abs_lut_input.disable_fr == 0,
+                            lighting.lut_scale.fr, LightingRegs::LightingSampler::Fresnel);
+
+            // Enabled for diffuse lighting alpha component
+            if (lighting.config0.fresnel_selector ==
+                    LightingRegs::LightingFresnelSelector::PrimaryAlpha ||
+                lighting.config0.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) {
+                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;
+            }
+        }
+
+        auto dot_product = Math::Dot(light_vector, normal);
+
+        // Calculate clamp highlights before applying the two-sided diffuse configuration to the dot
+        // product.
+        float clamp_highlights = 1.0f;
+        if (lighting.config0.clamp_highlights) {
+            if (dot_product <= 0.0f)
+                clamp_highlights = 0.0f;
+            else
+                clamp_highlights = 1.0f;
+        }
+
+        if (light_config.config.two_sided_diffuse)
+            dot_product = std::abs(dot_product);
+        else
+            dot_product = std::max(dot_product, 0.0f);
+
+        auto diffuse =
+            light_config.diffuse.ToVec3f() * dot_product + light_config.ambient.ToVec3f();
+        diffuse_sum += Math::MakeVec(diffuse * dist_atten, 0.0f);
+
+        specular_sum +=
+            Math::MakeVec((specular_0 + specular_1) * clamp_highlights * dist_atten, 0.0f);
+    }
+
+    diffuse_sum += Math::MakeVec(lighting.global_ambient.ToVec3f(), 0.0f);
+
+    auto diffuse = Math::MakeVec<float>(MathUtil::Clamp(diffuse_sum.x, 0.0f, 1.0f) * 255,
+                                        MathUtil::Clamp(diffuse_sum.y, 0.0f, 1.0f) * 255,
+                                        MathUtil::Clamp(diffuse_sum.z, 0.0f, 1.0f) * 255,
+                                        MathUtil::Clamp(diffuse_sum.w, 0.0f, 1.0f) * 255)
+                       .Cast<u8>();
+    auto specular = Math::MakeVec<float>(MathUtil::Clamp(specular_sum.x, 0.0f, 1.0f) * 255,
+                                         MathUtil::Clamp(specular_sum.y, 0.0f, 1.0f) * 255,
+                                         MathUtil::Clamp(specular_sum.z, 0.0f, 1.0f) * 255,
+                                         MathUtil::Clamp(specular_sum.w, 0.0f, 1.0f) * 255)
+                        .Cast<u8>();
+    return {diffuse, specular};
+}
+
+} // namespace Pica
diff --git a/src/video_core/swrasterizer/fragment_lighting.h b/src/video_core/swrasterizer/fragment_lighting.h
new file mode 100644
index 000000000..438dca926
--- /dev/null
+++ b/src/video_core/swrasterizer/fragment_lighting.h
@@ -0,0 +1,18 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <tuple>
+#include "common/quaternion.h"
+#include "common/vector_math.h"
+#include "video_core/pica_state.h"
+
+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);
+
+} // namespace Pica
diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index aee630954..bc7e1c56c 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -24,6 +24,7 @@
 #include "video_core/regs_rasterizer.h"
 #include "video_core/regs_texturing.h"
 #include "video_core/shader/shader.h"
+#include "video_core/swrasterizer/fragment_lighting.h"
 #include "video_core/swrasterizer/framebuffer.h"
 #include "video_core/swrasterizer/proctex.h"
 #include "video_core/swrasterizer/rasterizer.h"
@@ -115,246 +116,6 @@ static std::tuple<float24, float24, PAddr> ConvertCubeCoord(float24 u, float24 v
     return std::make_tuple(x / z * half + half, y / z * half + half, addr);
 }
 
-static float LookupLightingLut(const Pica::State::Lighting& lighting, size_t lut_index, u8 index,
-                               float delta) {
-    ASSERT_MSG(lut_index < lighting.luts.size(), "Out of range lut");
-    ASSERT_MSG(index < lighting.luts[lut_index].size(), "Out of range index");
-
-    const auto& lut = lighting.luts[lut_index][index];
-
-    float lut_value = lut.ToFloat();
-    float lut_diff = lut.DiffToFloat();
-
-    return lut_value + lut_diff * delta;
-}
-
-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) {
-
-    // TODO(Subv): Bump mapping
-    Math::Vec3<float> surface_normal = {0.0f, 0.0f, 1.0f};
-
-    if (lighting.config0.bump_mode != LightingRegs::LightingBumpMode::None) {
-        LOG_CRITICAL(HW_GPU, "unimplemented bump mapping");
-        UNIMPLEMENTED();
-    }
-
-    // Use the normalized the quaternion when performing the rotation
-    auto normal = Math::QuaternionRotate(normquat, surface_normal);
-
-    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};
-
-    for (unsigned light_index = 0; light_index <= lighting.max_light_index; ++light_index) {
-        unsigned num = lighting.light_enable.GetNum(light_index);
-        const auto& light_config = lighting.light[num];
-
-        Math::Vec3<float> refl_value = {};
-        Math::Vec3<float> position = {float16::FromRaw(light_config.x).ToFloat32(),
-                                      float16::FromRaw(light_config.y).ToFloat32(),
-                                      float16::FromRaw(light_config.z).ToFloat32()};
-        Math::Vec3<float> light_vector;
-
-        if (light_config.config.directional)
-            light_vector = position;
-        else
-            light_vector = position + view;
-
-        light_vector.Normalize();
-
-        float dist_atten = 1.0f;
-        if (!lighting.IsDistAttenDisabled(num)) {
-            auto distance = (-view - position).Length();
-            float scale = Pica::float20::FromRaw(light_config.dist_atten_scale).ToFloat32();
-            float bias = Pica::float20::FromRaw(light_config.dist_atten_bias).ToFloat32();
-            size_t lut =
-                static_cast<size_t>(LightingRegs::LightingSampler::DistanceAttenuation) + num;
-
-            float sample_loc = MathUtil::Clamp(scale * distance + bias, 0.0f, 1.0f);
-
-            u8 lutindex =
-                static_cast<u8>(MathUtil::Clamp(std::floor(sample_loc * 256.0f), 0.0f, 255.0f));
-            float delta = sample_loc * 256 - lutindex;
-            dist_atten = LookupLightingLut(lighting_state, lut, lutindex, delta);
-        }
-
-        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);
-                break;
-
-            case LightingRegs::LightingLutInput::VH:
-                result = Math::Dot(norm_view, half_angle);
-                break;
-
-            case LightingRegs::LightingLutInput::NV:
-                result = Math::Dot(normal, norm_view);
-                break;
-
-            case LightingRegs::LightingLutInput::LN:
-                result = Math::Dot(light_vector, normal);
-                break;
-
-            default:
-                LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %u\n", static_cast<u32>(input));
-                UNIMPLEMENTED();
-                result = 0.0f;
-            }
-
-            u8 index;
-            float delta;
-
-            if (abs) {
-                if (light_config.config.two_sided_diffuse)
-                    result = std::abs(result);
-                else
-                    result = std::max(result, 0.0f);
-
-                float flr = std::floor(result * 256.0f);
-                index = static_cast<u8>(MathUtil::Clamp(flr, 0.0f, 255.0f));
-                delta = result * 256 - index;
-            } else {
-                float flr = std::floor(result * 128.0f);
-                s8 signed_index = static_cast<s8>(MathUtil::Clamp(flr, -128.0f, 127.0f));
-                delta = result * 128.0f - signed_index;
-                index = static_cast<u8>(signed_index);
-            }
-
-            float scale = lighting.lut_scale.GetScale(scale_enum);
-            return scale *
-                   LookupLightingLut(lighting_state, static_cast<size_t>(sampler), index, delta);
-        };
-
-        // Specular 0 component
-        float d0_lut_value = 1.0f;
-        if (lighting.config1.disable_lut_d0 == 0 &&
-            LightingRegs::IsLightingSamplerSupported(
-                lighting.config0.config, LightingRegs::LightingSampler::Distribution0)) {
-            d0_lut_value =
-                GetLutValue(lighting.lut_input.d0, lighting.abs_lut_input.disable_d0 == 0,
-                            lighting.lut_scale.d0, LightingRegs::LightingSampler::Distribution0);
-        }
-
-        Math::Vec3<float> specular_0 = d0_lut_value * light_config.specular_0.ToVec3f();
-
-        // If enabled, lookup ReflectRed value, otherwise, 1.0 is used
-        if (lighting.config1.disable_lut_rr == 0 &&
-            LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
-                                                     LightingRegs::LightingSampler::ReflectRed)) {
-            refl_value.x =
-                GetLutValue(lighting.lut_input.rr, lighting.abs_lut_input.disable_rr == 0,
-                            lighting.lut_scale.rr, LightingRegs::LightingSampler::ReflectRed);
-        } else {
-            refl_value.x = 1.0f;
-        }
-
-        // If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used
-        if (lighting.config1.disable_lut_rg == 0 &&
-            LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
-                                                     LightingRegs::LightingSampler::ReflectGreen)) {
-            refl_value.y =
-                GetLutValue(lighting.lut_input.rg, lighting.abs_lut_input.disable_rg == 0,
-                            lighting.lut_scale.rg, LightingRegs::LightingSampler::ReflectGreen);
-        } else {
-            refl_value.y = refl_value.x;
-        }
-
-        // If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used
-        if (lighting.config1.disable_lut_rb == 0 &&
-            LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
-                                                     LightingRegs::LightingSampler::ReflectBlue)) {
-            refl_value.z =
-                GetLutValue(lighting.lut_input.rb, lighting.abs_lut_input.disable_rb == 0,
-                            lighting.lut_scale.rb, LightingRegs::LightingSampler::ReflectBlue);
-        } else {
-            refl_value.z = refl_value.x;
-        }
-
-        // Specular 1 component
-        float d1_lut_value = 1.0f;
-        if (lighting.config1.disable_lut_d1 == 0 &&
-            LightingRegs::IsLightingSamplerSupported(
-                lighting.config0.config, LightingRegs::LightingSampler::Distribution1)) {
-            d1_lut_value =
-                GetLutValue(lighting.lut_input.d1, lighting.abs_lut_input.disable_d1 == 0,
-                            lighting.lut_scale.d1, LightingRegs::LightingSampler::Distribution1);
-        }
-
-        Math::Vec3<float> specular_1 =
-            d1_lut_value * refl_value * light_config.specular_1.ToVec3f();
-
-        // Fresnel
-        if (lighting.config1.disable_lut_fr == 0 &&
-            LightingRegs::IsLightingSamplerSupported(lighting.config0.config,
-                                                     LightingRegs::LightingSampler::Fresnel)) {
-
-            float lut_value =
-                GetLutValue(lighting.lut_input.fr, lighting.abs_lut_input.disable_fr == 0,
-                            lighting.lut_scale.fr, LightingRegs::LightingSampler::Fresnel);
-
-            // Enabled for diffuse lighting alpha component
-            if (lighting.config0.fresnel_selector ==
-                    LightingRegs::LightingFresnelSelector::PrimaryAlpha ||
-                lighting.config0.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) {
-                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;
-            }
-        }
-
-        auto dot_product = Math::Dot(light_vector, normal);
-
-        // Calculate clamp highlights before applying the two-sided diffuse configuration to the dot
-        // product.
-        float clamp_highlights = 1.0f;
-        if (lighting.config0.clamp_highlights) {
-            if (dot_product <= 0.0f)
-                clamp_highlights = 0.0f;
-            else
-                clamp_highlights = 1.0f;
-        }
-
-        if (light_config.config.two_sided_diffuse)
-            dot_product = std::abs(dot_product);
-        else
-            dot_product = std::max(dot_product, 0.0f);
-
-        auto diffuse =
-            light_config.diffuse.ToVec3f() * dot_product + light_config.ambient.ToVec3f();
-        diffuse_sum += Math::MakeVec(diffuse * dist_atten, 0.0f);
-
-        specular_sum +=
-            Math::MakeVec((specular_0 + specular_1) * clamp_highlights * dist_atten, 0.0f);
-    }
-
-    diffuse_sum += Math::MakeVec(lighting.global_ambient.ToVec3f(), 0.0f);
-
-    auto diffuse = Math::MakeVec<float>(MathUtil::Clamp(diffuse_sum.x, 0.0f, 1.0f) * 255,
-                                        MathUtil::Clamp(diffuse_sum.y, 0.0f, 1.0f) * 255,
-                                        MathUtil::Clamp(diffuse_sum.z, 0.0f, 1.0f) * 255,
-                                        MathUtil::Clamp(diffuse_sum.w, 0.0f, 1.0f) * 255)
-                       .Cast<u8>();
-    auto specular = Math::MakeVec<float>(MathUtil::Clamp(specular_sum.x, 0.0f, 1.0f) * 255,
-                                         MathUtil::Clamp(specular_sum.y, 0.0f, 1.0f) * 255,
-                                         MathUtil::Clamp(specular_sum.z, 0.0f, 1.0f) * 255,
-                                         MathUtil::Clamp(specular_sum.w, 0.0f, 1.0f) * 255)
-                        .Cast<u8>();
-    return {diffuse, specular};
-}
-
 MICROPROFILE_DEFINE(GPU_Rasterization, "GPU", "Rasterization", MP_RGB(50, 50, 240));
 
 /**

From 2252a63f8036cdf2612243271ce29e6104f82825 Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Thu, 3 Aug 2017 12:01:31 +0300
Subject: [PATCH 27/27] SwRasterizer/Lighting: shorten file name

---
 src/video_core/CMakeLists.txt                                 | 4 ++--
 .../swrasterizer/{fragment_lighting.cpp => lighting.cpp}      | 2 +-
 .../swrasterizer/{fragment_lighting.h => lighting.h}          | 0
 src/video_core/swrasterizer/rasterizer.cpp                    | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)
 rename src/video_core/swrasterizer/{fragment_lighting.cpp => lighting.cpp} (99%)
 rename src/video_core/swrasterizer/{fragment_lighting.h => lighting.h} (100%)

diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index b2280f2ef..cffa4c952 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -14,8 +14,8 @@ set(SRCS
             shader/shader.cpp
             shader/shader_interpreter.cpp
             swrasterizer/clipper.cpp
-            swrasterizer/fragment_lighting.cpp
             swrasterizer/framebuffer.cpp
+            swrasterizer/lighting.cpp
             swrasterizer/proctex.cpp
             swrasterizer/rasterizer.cpp
             swrasterizer/swrasterizer.cpp
@@ -55,8 +55,8 @@ set(HEADERS
             shader/shader.h
             shader/shader_interpreter.h
             swrasterizer/clipper.h
-            swrasterizer/fragment_lighting.h
             swrasterizer/framebuffer.h
+            swrasterizer/lighting.h
             swrasterizer/proctex.h
             swrasterizer/rasterizer.h
             swrasterizer/swrasterizer.h
diff --git a/src/video_core/swrasterizer/fragment_lighting.cpp b/src/video_core/swrasterizer/lighting.cpp
similarity index 99%
rename from src/video_core/swrasterizer/fragment_lighting.cpp
rename to src/video_core/swrasterizer/lighting.cpp
index 45a86b5cd..63088eee8 100644
--- a/src/video_core/swrasterizer/fragment_lighting.cpp
+++ b/src/video_core/swrasterizer/lighting.cpp
@@ -3,7 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "common/math_util.h"
-#include "video_core/swrasterizer/fragment_lighting.h"
+#include "video_core/swrasterizer/lighting.h"
 
 namespace Pica {
 
diff --git a/src/video_core/swrasterizer/fragment_lighting.h b/src/video_core/swrasterizer/lighting.h
similarity index 100%
rename from src/video_core/swrasterizer/fragment_lighting.h
rename to src/video_core/swrasterizer/lighting.h
diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index bc7e1c56c..fdc1df199 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -24,8 +24,8 @@
 #include "video_core/regs_rasterizer.h"
 #include "video_core/regs_texturing.h"
 #include "video_core/shader/shader.h"
-#include "video_core/swrasterizer/fragment_lighting.h"
 #include "video_core/swrasterizer/framebuffer.h"
+#include "video_core/swrasterizer/lighting.h"
 #include "video_core/swrasterizer/proctex.h"
 #include "video_core/swrasterizer/rasterizer.h"
 #include "video_core/swrasterizer/texturing.h"