|
|
|
@ -287,7 +287,7 @@ static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) {
|
|
|
|
|
|
|
|
|
|
/// Writes the code to emulate the specified TEV stage
|
|
|
|
|
static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) {
|
|
|
|
|
const auto stage = static_cast<const Pica::Regs::TevStageConfig>(config.tev_stages[index]);
|
|
|
|
|
const auto stage = static_cast<const Pica::Regs::TevStageConfig>(config.state.tev_stages[index]);
|
|
|
|
|
if (!IsPassThroughTevStage(stage)) {
|
|
|
|
|
std::string index_name = std::to_string(index);
|
|
|
|
|
|
|
|
|
@ -331,6 +331,8 @@ static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsi
|
|
|
|
|
|
|
|
|
|
/// Writes the code to emulate fragment lighting
|
|
|
|
|
static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
|
|
|
|
|
const auto& lighting = config.state.lighting;
|
|
|
|
|
|
|
|
|
|
// Define lighting globals
|
|
|
|
|
out += "vec4 diffuse_sum = vec4(0.0, 0.0, 0.0, 1.0);\n"
|
|
|
|
|
"vec4 specular_sum = vec4(0.0, 0.0, 0.0, 1.0);\n"
|
|
|
|
@ -338,17 +340,17 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
|
|
|
|
|
"vec3 refl_value = vec3(0.0);\n";
|
|
|
|
|
|
|
|
|
|
// Compute fragment normals
|
|
|
|
|
if (config.lighting.bump_mode == Pica::Regs::LightingBumpMode::NormalMap) {
|
|
|
|
|
if (lighting.bump_mode == Pica::Regs::LightingBumpMode::NormalMap) {
|
|
|
|
|
// Bump mapping is enabled using a normal map, read perturbation vector from the selected texture
|
|
|
|
|
std::string bump_selector = std::to_string(config.lighting.bump_selector);
|
|
|
|
|
std::string bump_selector = std::to_string(lighting.bump_selector);
|
|
|
|
|
out += "vec3 surface_normal = 2.0 * texture(tex[" + bump_selector + "], texcoord[" + bump_selector + "]).rgb - 1.0;\n";
|
|
|
|
|
|
|
|
|
|
// Recompute Z-component of perturbation if 'renorm' is enabled, this provides a higher precision result
|
|
|
|
|
if (config.lighting.bump_renorm) {
|
|
|
|
|
if (lighting.bump_renorm) {
|
|
|
|
|
std::string val = "(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))";
|
|
|
|
|
out += "surface_normal.z = sqrt(max(" + val + ", 0.0));\n";
|
|
|
|
|
}
|
|
|
|
|
} else if (config.lighting.bump_mode == Pica::Regs::LightingBumpMode::TangentMap) {
|
|
|
|
|
} else if (lighting.bump_mode == Pica::Regs::LightingBumpMode::TangentMap) {
|
|
|
|
|
// Bump mapping is enabled using a tangent map
|
|
|
|
|
LOG_CRITICAL(HW_GPU, "unimplemented bump mapping mode (tangent mapping)");
|
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
@ -361,7 +363,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
|
|
|
|
|
out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n";
|
|
|
|
|
|
|
|
|
|
// Gets the index into the specified lookup table for specular lighting
|
|
|
|
|
auto GetLutIndex = [config](unsigned light_num, Regs::LightingLutInput input, bool abs) {
|
|
|
|
|
auto GetLutIndex = [&lighting](unsigned light_num, Regs::LightingLutInput input, bool abs) {
|
|
|
|
|
const std::string half_angle = "normalize(normalize(view) + light_vector)";
|
|
|
|
|
std::string index;
|
|
|
|
|
switch (input) {
|
|
|
|
@ -389,7 +391,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.lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)";
|
|
|
|
|
index = lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)";
|
|
|
|
|
return "(FLOAT_255 * clamp(" + index + ", 0.0, 1.0))";
|
|
|
|
|
} else {
|
|
|
|
|
// LUT index is in the range of (-1.0, 1.0)
|
|
|
|
@ -407,8 +409,8 @@ 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.lighting.src_num; ++light_index) {
|
|
|
|
|
const auto& light_config = config.lighting.light[light_index];
|
|
|
|
|
for (unsigned light_index = 0; light_index < lighting.src_num; ++light_index) {
|
|
|
|
|
const auto& light_config = lighting.light[light_index];
|
|
|
|
|
std::string light_src = "light_src[" + std::to_string(light_config.num) + "]";
|
|
|
|
|
|
|
|
|
|
// Compute light vector (directional or positional)
|
|
|
|
@ -432,39 +434,39 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If enabled, clamp specular component if lighting result is negative
|
|
|
|
|
std::string clamp_highlights = config.lighting.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0";
|
|
|
|
|
std::string clamp_highlights = lighting.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0";
|
|
|
|
|
|
|
|
|
|
// Specular 0 component
|
|
|
|
|
std::string d0_lut_value = "1.0";
|
|
|
|
|
if (config.lighting.lut_d0.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::Distribution0)) {
|
|
|
|
|
if (lighting.lut_d0.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Distribution0)) {
|
|
|
|
|
// Lookup specular "distribution 0" LUT value
|
|
|
|
|
std::string index = GetLutIndex(light_config.num, config.lighting.lut_d0.type, config.lighting.lut_d0.abs_input);
|
|
|
|
|
d0_lut_value = "(" + std::to_string(config.lighting.lut_d0.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution0, index) + ")";
|
|
|
|
|
std::string index = GetLutIndex(light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input);
|
|
|
|
|
d0_lut_value = "(" + std::to_string(lighting.lut_d0.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution0, index) + ")";
|
|
|
|
|
}
|
|
|
|
|
std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)";
|
|
|
|
|
|
|
|
|
|
// If enabled, lookup ReflectRed value, otherwise, 1.0 is used
|
|
|
|
|
if (config.lighting.lut_rr.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::ReflectRed)) {
|
|
|
|
|
std::string index = GetLutIndex(light_config.num, config.lighting.lut_rr.type, config.lighting.lut_rr.abs_input);
|
|
|
|
|
std::string value = "(" + std::to_string(config.lighting.lut_rr.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectRed, index) + ")";
|
|
|
|
|
if (lighting.lut_rr.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectRed)) {
|
|
|
|
|
std::string index = GetLutIndex(light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input);
|
|
|
|
|
std::string value = "(" + std::to_string(lighting.lut_rr.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectRed, index) + ")";
|
|
|
|
|
out += "refl_value.r = " + value + ";\n";
|
|
|
|
|
} else {
|
|
|
|
|
out += "refl_value.r = 1.0;\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used
|
|
|
|
|
if (config.lighting.lut_rg.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::ReflectGreen)) {
|
|
|
|
|
std::string index = GetLutIndex(light_config.num, config.lighting.lut_rg.type, config.lighting.lut_rg.abs_input);
|
|
|
|
|
std::string value = "(" + std::to_string(config.lighting.lut_rg.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectGreen, index) + ")";
|
|
|
|
|
if (lighting.lut_rg.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectGreen)) {
|
|
|
|
|
std::string index = GetLutIndex(light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input);
|
|
|
|
|
std::string value = "(" + std::to_string(lighting.lut_rg.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectGreen, index) + ")";
|
|
|
|
|
out += "refl_value.g = " + value + ";\n";
|
|
|
|
|
} else {
|
|
|
|
|
out += "refl_value.g = refl_value.r;\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used
|
|
|
|
|
if (config.lighting.lut_rb.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::ReflectBlue)) {
|
|
|
|
|
std::string index = GetLutIndex(light_config.num, config.lighting.lut_rb.type, config.lighting.lut_rb.abs_input);
|
|
|
|
|
std::string value = "(" + std::to_string(config.lighting.lut_rb.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectBlue, index) + ")";
|
|
|
|
|
if (lighting.lut_rb.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectBlue)) {
|
|
|
|
|
std::string index = GetLutIndex(light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input);
|
|
|
|
|
std::string value = "(" + std::to_string(lighting.lut_rb.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectBlue, index) + ")";
|
|
|
|
|
out += "refl_value.b = " + value + ";\n";
|
|
|
|
|
} else {
|
|
|
|
|
out += "refl_value.b = refl_value.r;\n";
|
|
|
|
@ -472,27 +474,27 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
|
|
|
|
|
|
|
|
|
|
// Specular 1 component
|
|
|
|
|
std::string d1_lut_value = "1.0";
|
|
|
|
|
if (config.lighting.lut_d1.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::Distribution1)) {
|
|
|
|
|
if (lighting.lut_d1.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Distribution1)) {
|
|
|
|
|
// Lookup specular "distribution 1" LUT value
|
|
|
|
|
std::string index = GetLutIndex(light_config.num, config.lighting.lut_d1.type, config.lighting.lut_d1.abs_input);
|
|
|
|
|
d1_lut_value = "(" + std::to_string(config.lighting.lut_d1.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution1, index) + ")";
|
|
|
|
|
std::string index = GetLutIndex(light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input);
|
|
|
|
|
d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution1, index) + ")";
|
|
|
|
|
}
|
|
|
|
|
std::string specular_1 = "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)";
|
|
|
|
|
|
|
|
|
|
// Fresnel
|
|
|
|
|
if (config.lighting.lut_fr.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::Fresnel)) {
|
|
|
|
|
if (lighting.lut_fr.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Fresnel)) {
|
|
|
|
|
// Lookup fresnel LUT value
|
|
|
|
|
std::string index = GetLutIndex(light_config.num, config.lighting.lut_fr.type, config.lighting.lut_fr.abs_input);
|
|
|
|
|
std::string value = "(" + std::to_string(config.lighting.lut_fr.scale) + " * " + GetLutValue(Regs::LightingSampler::Fresnel, index) + ")";
|
|
|
|
|
std::string index = GetLutIndex(light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input);
|
|
|
|
|
std::string value = "(" + std::to_string(lighting.lut_fr.scale) + " * " + GetLutValue(Regs::LightingSampler::Fresnel, index) + ")";
|
|
|
|
|
|
|
|
|
|
// Enabled for difffuse lighting alpha component
|
|
|
|
|
if (config.lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha ||
|
|
|
|
|
config.lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both)
|
|
|
|
|
if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha ||
|
|
|
|
|
lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both)
|
|
|
|
|
out += "diffuse_sum.a *= " + value + ";\n";
|
|
|
|
|
|
|
|
|
|
// Enabled for the specular lighting alpha component
|
|
|
|
|
if (config.lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::SecondaryAlpha ||
|
|
|
|
|
config.lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both)
|
|
|
|
|
if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::SecondaryAlpha ||
|
|
|
|
|
lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both)
|
|
|
|
|
out += "specular_sum.a *= " + value + ";\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -510,6 +512,8 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string GenerateFragmentShader(const PicaShaderConfig& config) {
|
|
|
|
|
const auto& state = config.state;
|
|
|
|
|
|
|
|
|
|
std::string out = R"(
|
|
|
|
|
#version 330 core
|
|
|
|
|
#define NUM_TEV_STAGES 6
|
|
|
|
@ -555,24 +559,24 @@ vec4 secondary_fragment_color = vec4(0.0);
|
|
|
|
|
)";
|
|
|
|
|
|
|
|
|
|
// 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) {
|
|
|
|
|
if (state.alpha_test_func == Regs::CompareFunc::Never) {
|
|
|
|
|
out += "discard; }";
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (config.lighting.enable)
|
|
|
|
|
if (state.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";
|
|
|
|
|
|
|
|
|
|
for (size_t index = 0; index < config.tev_stages.size(); ++index)
|
|
|
|
|
for (size_t index = 0; index < state.tev_stages.size(); ++index)
|
|
|
|
|
WriteTevStage(out, config, (unsigned)index);
|
|
|
|
|
|
|
|
|
|
if (config.alpha_test_func != Regs::CompareFunc::Always) {
|
|
|
|
|
if (state.alpha_test_func != Regs::CompareFunc::Always) {
|
|
|
|
|
out += "if (";
|
|
|
|
|
AppendAlphaTestCondition(out, config.alpha_test_func);
|
|
|
|
|
AppendAlphaTestCondition(out, state.alpha_test_func);
|
|
|
|
|
out += ") discard;\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|