diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 48854dda2..b1cf072f1 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -718,6 +718,8 @@ struct Regs { }; union { + BitField<16, 1, u32> lut_enable_d0; // 0: GL_TRUE, 1: GL_FALSE + // Each bit specifies whether distance attenuation should be applied for the // corresponding light diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 6be161efd..2042be786 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -73,23 +73,24 @@ struct PicaShaderConfig { // Fragment lighting - res.lighting_enabled = !regs.lighting.disable; - res.num_lights = regs.lighting.src_num + 1; + res.lighting.enable = !regs.lighting.disable; + res.lighting.src_num = regs.lighting.src_num + 1; - for (unsigned light_index = 0; light_index < res.num_lights; ++light_index) { + for (unsigned light_index = 0; light_index < res.lighting.src_num; ++light_index) { unsigned num = regs.lighting.light_enable.GetNum(light_index); const auto& light = regs.lighting.light[num]; - res.light_src[light_index].num = num; - res.light_src[light_index].directional = light.directional != 0; - res.light_src[light_index].two_sided_diffuse = light.two_sided_diffuse != 0; - res.light_src[light_index].dist_atten_enabled = regs.lighting.IsDistAttenEnabled(num); - res.light_src[light_index].dist_atten_bias = Pica::float20::FromRawFloat20(light.dist_atten_bias).ToFloat32(); - res.light_src[light_index].dist_atten_scale = Pica::float20::FromRawFloat20(light.dist_atten_scale).ToFloat32(); + res.lighting.light[light_index].num = num; + res.lighting.light[light_index].directional = light.directional != 0; + res.lighting.light[light_index].two_sided_diffuse = light.two_sided_diffuse != 0; + res.lighting.light[light_index].dist_atten_enable = regs.lighting.IsDistAttenEnabled(num); + res.lighting.light[light_index].dist_atten_bias = Pica::float20::FromRawFloat20(light.dist_atten_bias).ToFloat32(); + res.lighting.light[light_index].dist_atten_scale = Pica::float20::FromRawFloat20(light.dist_atten_scale).ToFloat32(); } - res.lighting_lut.d0_abs = regs.lighting.abs_lut_input.d0 == 0; - res.lighting_lut.d0_type = (Pica::Regs::LightingLutInput)regs.lighting.lut_input.d0.Value(); - res.clamp_highlights = regs.lighting.clamp_highlights != 0; + res.lighting.lut_d0.enable = regs.lighting.lut_enable_d0 == 0; + res.lighting.lut_d0.abs_input = regs.lighting.abs_lut_input.d0 == 0; + res.lighting.lut_d0.type = (Pica::Regs::LightingLutInput)regs.lighting.lut_input.d0.Value(); + res.lighting.clamp_highlights = regs.lighting.clamp_highlights != 0; return res; } @@ -112,22 +113,25 @@ struct PicaShaderConfig { u8 combiner_buffer_input = 0; struct { - unsigned num = 0; - bool directional = false; - bool two_sided_diffuse = false; - bool dist_atten_enabled = false; - GLfloat dist_atten_scale = 0.0f; - GLfloat dist_atten_bias = 0.0f; - } light_src[8]; + struct { + unsigned num = 0; + bool directional = false; + bool two_sided_diffuse = false; + bool dist_atten_enable = false; + GLfloat dist_atten_scale = 0.0f; + GLfloat dist_atten_bias = 0.0f; + } light[8]; - bool lighting_enabled = false; - unsigned num_lights = 0; - bool clamp_highlights = false; + bool enable = false; + unsigned src_num = 0; + bool clamp_highlights = false; - struct { - bool d0_abs = false; - Pica::Regs::LightingLutInput d0_type = Pica::Regs::LightingLutInput::NH; - } lighting_lut; + struct { + bool enable = false; + bool abs_input = false; + Pica::Regs::LightingLutInput type = Pica::Regs::LightingLutInput::NH; + } lut_d0; + } lighting; }; }; diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 10cb2d065..a2770cc6e 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -360,7 +360,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { if (abs) { // LUT index is in the range of (0.0, 1.0) - index = config.light_src[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)"; + index = config.lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)"; return "clamp(" + index + ", 0.0, FLOAT_255)"; } else { // LUT index is in the range of (-1.0, 1.0) @@ -378,10 +378,9 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { }; // Write the code to emulate each enabled light - for (unsigned light_index = 0; light_index < config.num_lights; ++light_index) { - unsigned num = config.light_src[light_index].num; - const auto& light_config = config.light_src[light_index]; - std::string light_src = "light_src[" + std::to_string(num) + "]"; + for (unsigned light_index = 0; light_index < config.lighting.src_num; ++light_index) { + const auto& light_config = config.lighting.light[light_index]; + std::string light_src = "light_src[" + std::to_string(light_config.num) + "]"; // Compute light vector (directional or positional) if (light_config.directional) @@ -394,12 +393,12 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { // If enabled, compute distance attenuation value std::string dist_atten = "1.0"; - if (light_config.dist_atten_enabled) { + if (light_config.dist_atten_enable) { std::string scale = std::to_string(light_config.dist_atten_scale); std::string bias = std::to_string(light_config.dist_atten_bias); std::string lut_index = "(" + scale + " * length(-view - " + light_src + ".position) + " + bias + ")"; lut_index = "((clamp(" + lut_index + ", 0.0, FLOAT_255)))"; - const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + num); + const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + light_config.num); dist_atten = GetLutValue((Regs::LightingSampler)lut_num, lut_index); } @@ -407,11 +406,14 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { out += "diffuse_sum += ((" + light_src + ".diffuse * " + dot_product + ") + " + light_src + ".ambient) * " + dist_atten + ";\n"; // If enabled, clamp specular component if lighting result is negative - std::string clamp_highlights = config.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0"; + std::string clamp_highlights = config.lighting.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0"; - // Lookup specular distribution 0 LUT value - std::string d0_lut_index = GetLutIndex(num, config.lighting_lut.d0_type, config.lighting_lut.d0_abs); - std::string d0_lut_value = GetLutValue(Regs::LightingSampler::Distribution0, d0_lut_index); + // Lookup specular "distribution 0" LUT value + std::string d0_lut_value = "1.0"; + if (config.lighting.lut_d0.enable) { + std::string d0_lut_index = GetLutIndex(light_config.num, config.lighting.lut_d0.type, config.lighting.lut_d0.abs_input); + d0_lut_value = GetLutValue(Regs::LightingSampler::Distribution0, d0_lut_index); + } // Compute secondary fragment color (specular lighting) function out += "specular_sum += " + clamp_highlights + " * " + d0_lut_value + " * " + light_src + ".specular_0 * " + dist_atten + ";\n"; @@ -463,15 +465,15 @@ vec4 primary_fragment_color = vec4(0.0); vec4 secondary_fragment_color = vec4(0.0); )"; - if (config.lighting_enabled) - WriteLighting(out, config); - // Do not do any sort of processing if it's obvious we're not going to pass the alpha test if (config.alpha_test_func == Regs::CompareFunc::Never) { out += "discard; }"; return out; } + if (config.lighting.enable) + WriteLighting(out, config); + out += "vec4 combiner_buffer = vec4(0.0);\n"; out += "vec4 next_combiner_buffer = tev_combiner_buffer_color;\n"; out += "vec4 last_tex_env_out = vec4(0.0);\n";