2015-10-06 04:33:47 +02:00
|
|
|
// Copyright 2015 Citra Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2016-04-30 17:34:51 +02:00
|
|
|
#include <array>
|
|
|
|
#include <cstddef>
|
|
|
|
|
|
|
|
#include "common/assert.h"
|
|
|
|
#include "common/bit_field.h"
|
|
|
|
#include "common/logging/log.h"
|
|
|
|
|
2015-10-06 04:33:47 +02:00
|
|
|
#include "video_core/pica.h"
|
|
|
|
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
|
|
|
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
2016-04-30 17:34:51 +02:00
|
|
|
#include "video_core/renderer_opengl/gl_shader_util.h"
|
2015-10-06 04:33:47 +02:00
|
|
|
|
2015-10-07 00:01:53 +02:00
|
|
|
using Pica::Regs;
|
|
|
|
using TevStageConfig = Regs::TevStageConfig;
|
|
|
|
|
2015-10-06 04:33:47 +02:00
|
|
|
namespace GLShader {
|
|
|
|
|
2015-10-07 00:21:28 +02:00
|
|
|
/// Detects if a TEV stage is configured to be skipped (to avoid generating unnecessary code)
|
2015-10-07 00:01:53 +02:00
|
|
|
static bool IsPassThroughTevStage(const TevStageConfig& stage) {
|
|
|
|
return (stage.color_op == TevStageConfig::Operation::Replace &&
|
|
|
|
stage.alpha_op == TevStageConfig::Operation::Replace &&
|
|
|
|
stage.color_source1 == TevStageConfig::Source::Previous &&
|
|
|
|
stage.alpha_source1 == TevStageConfig::Source::Previous &&
|
|
|
|
stage.color_modifier1 == TevStageConfig::ColorModifier::SourceColor &&
|
|
|
|
stage.alpha_modifier1 == TevStageConfig::AlphaModifier::SourceAlpha &&
|
|
|
|
stage.GetColorMultiplier() == 1 &&
|
|
|
|
stage.GetAlphaMultiplier() == 1);
|
2015-10-06 04:33:47 +02:00
|
|
|
}
|
|
|
|
|
2015-10-07 00:21:28 +02:00
|
|
|
/// Writes the specified TEV stage source component(s)
|
2016-04-19 00:53:42 +02:00
|
|
|
static void AppendSource(std::string& out, const PicaShaderConfig& config, TevStageConfig::Source source,
|
2015-10-07 00:01:53 +02:00
|
|
|
const std::string& index_name) {
|
2016-04-19 00:53:42 +02:00
|
|
|
const auto& state = config.state;
|
2015-10-07 00:01:53 +02:00
|
|
|
using Source = TevStageConfig::Source;
|
2015-10-06 04:33:47 +02:00
|
|
|
switch (source) {
|
|
|
|
case Source::PrimaryColor:
|
2015-10-13 04:23:26 +02:00
|
|
|
out += "primary_color";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Source::PrimaryFragmentColor:
|
2015-11-12 23:33:21 +01:00
|
|
|
out += "primary_fragment_color";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Source::SecondaryFragmentColor:
|
2015-11-15 05:23:08 +01:00
|
|
|
out += "secondary_fragment_color";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Source::Texture0:
|
2016-04-19 00:53:42 +02:00
|
|
|
// Only unit 0 respects the texturing type (according to 3DBrew)
|
|
|
|
switch(state.texture0_type) {
|
|
|
|
case Pica::Regs::TextureConfig::Texture2D:
|
|
|
|
out += "texture(tex[0], texcoord[0])";
|
|
|
|
break;
|
|
|
|
case Pica::Regs::TextureConfig::Projection2D:
|
|
|
|
out += "textureProj(tex[0], vec3(texcoord[0], texcoord0_w))";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
out += "texture(tex[0], texcoord[0])";
|
|
|
|
LOG_CRITICAL(HW_GPU, "Unhandled texture type %x", static_cast<int>(state.texture0_type));
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
break;
|
|
|
|
}
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Source::Texture1:
|
2015-10-13 04:23:26 +02:00
|
|
|
out += "texture(tex[1], texcoord[1])";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
2015-10-13 04:23:26 +02:00
|
|
|
case Source::Texture2:
|
|
|
|
out += "texture(tex[2], texcoord[2])";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Source::PreviousBuffer:
|
2015-10-13 04:23:26 +02:00
|
|
|
out += "combiner_buffer";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Source::Constant:
|
2015-10-13 04:23:26 +02:00
|
|
|
((out += "const_color[") += index_name) += ']';
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Source::Previous:
|
2015-10-13 04:23:26 +02:00
|
|
|
out += "last_tex_env_out";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
default:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "vec4(0.0)";
|
2015-10-06 04:33:47 +02:00
|
|
|
LOG_CRITICAL(Render_OpenGL, "Unknown source op %u", source);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-07 00:21:28 +02:00
|
|
|
/// Writes the color components to use for the specified TEV stage color modifier
|
2016-04-19 00:53:42 +02:00
|
|
|
static void AppendColorModifier(std::string& out, const PicaShaderConfig& config, TevStageConfig::ColorModifier modifier,
|
2015-10-07 00:01:53 +02:00
|
|
|
TevStageConfig::Source source, const std::string& index_name) {
|
|
|
|
using ColorModifier = TevStageConfig::ColorModifier;
|
2015-10-06 04:33:47 +02:00
|
|
|
switch (modifier) {
|
|
|
|
case ColorModifier::SourceColor:
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".rgb";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case ColorModifier::OneMinusSourceColor:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "vec3(1.0) - ";
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".rgb";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case ColorModifier::SourceAlpha:
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".aaa";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case ColorModifier::OneMinusSourceAlpha:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "vec3(1.0) - ";
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".aaa";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case ColorModifier::SourceRed:
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".rrr";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case ColorModifier::OneMinusSourceRed:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "vec3(1.0) - ";
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".rrr";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case ColorModifier::SourceGreen:
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".ggg";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case ColorModifier::OneMinusSourceGreen:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "vec3(1.0) - ";
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".ggg";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case ColorModifier::SourceBlue:
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".bbb";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case ColorModifier::OneMinusSourceBlue:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "vec3(1.0) - ";
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".bbb";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
default:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "vec3(0.0)";
|
2015-10-06 04:33:47 +02:00
|
|
|
LOG_CRITICAL(Render_OpenGL, "Unknown color modifier op %u", modifier);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-07 00:21:28 +02:00
|
|
|
/// Writes the alpha component to use for the specified TEV stage alpha modifier
|
2016-04-19 00:53:42 +02:00
|
|
|
static void AppendAlphaModifier(std::string& out, const PicaShaderConfig& config, TevStageConfig::AlphaModifier modifier,
|
2015-10-07 00:01:53 +02:00
|
|
|
TevStageConfig::Source source, const std::string& index_name) {
|
|
|
|
using AlphaModifier = TevStageConfig::AlphaModifier;
|
2015-10-06 04:33:47 +02:00
|
|
|
switch (modifier) {
|
|
|
|
case AlphaModifier::SourceAlpha:
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".a";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case AlphaModifier::OneMinusSourceAlpha:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "1.0 - ";
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".a";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case AlphaModifier::SourceRed:
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".r";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case AlphaModifier::OneMinusSourceRed:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "1.0 - ";
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".r";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case AlphaModifier::SourceGreen:
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".g";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case AlphaModifier::OneMinusSourceGreen:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "1.0 - ";
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".g";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case AlphaModifier::SourceBlue:
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".b";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case AlphaModifier::OneMinusSourceBlue:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "1.0 - ";
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendSource(out, config, source, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ".b";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
default:
|
2015-10-08 03:02:50 +02:00
|
|
|
out += "0.0";
|
2015-10-06 04:33:47 +02:00
|
|
|
LOG_CRITICAL(Render_OpenGL, "Unknown alpha modifier op %u", modifier);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-07 00:21:28 +02:00
|
|
|
/// Writes the combiner function for the color components for the specified TEV stage operation
|
2015-10-07 00:01:53 +02:00
|
|
|
static void AppendColorCombiner(std::string& out, TevStageConfig::Operation operation,
|
2015-10-06 04:33:47 +02:00
|
|
|
const std::string& variable_name) {
|
2015-10-13 04:23:26 +02:00
|
|
|
out += "clamp(";
|
2015-10-07 00:01:53 +02:00
|
|
|
using Operation = TevStageConfig::Operation;
|
2015-10-06 04:33:47 +02:00
|
|
|
switch (operation) {
|
|
|
|
case Operation::Replace:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += variable_name + "[0]";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Operation::Modulate:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += variable_name + "[0] * " + variable_name + "[1]";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Operation::Add:
|
2015-10-13 04:23:26 +02:00
|
|
|
out += variable_name + "[0] + " + variable_name + "[1]";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Operation::AddSigned:
|
2015-10-13 04:23:26 +02:00
|
|
|
out += variable_name + "[0] + " + variable_name + "[1] - vec3(0.5)";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Operation::Lerp:
|
2015-10-13 04:23:26 +02:00
|
|
|
// TODO(bunnei): Verify if HW actually does this per-component, otherwise we can just use builtin lerp
|
2015-10-07 00:01:53 +02:00
|
|
|
out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (vec3(1.0) - " + variable_name + "[2])";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Operation::Subtract:
|
2015-10-13 04:23:26 +02:00
|
|
|
out += variable_name + "[0] - " + variable_name + "[1]";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Operation::MultiplyThenAdd:
|
2015-10-13 04:23:26 +02:00
|
|
|
out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Operation::AddThenMultiply:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " + variable_name + "[2]";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
2016-04-08 23:16:51 +02:00
|
|
|
case Operation::Dot3_RGB:
|
|
|
|
out += "vec3(dot(" + variable_name + "[0] - vec3(0.5), " + variable_name + "[1] - vec3(0.5)) * 4.0)";
|
|
|
|
break;
|
2015-10-06 04:33:47 +02:00
|
|
|
default:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "vec3(0.0)";
|
|
|
|
LOG_CRITICAL(Render_OpenGL, "Unknown color combiner operation: %u", operation);
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
}
|
2015-10-21 06:04:02 +02:00
|
|
|
out += ", vec3(0.0), vec3(1.0))"; // Clamp result to 0.0, 1.0
|
2015-10-06 04:33:47 +02:00
|
|
|
}
|
|
|
|
|
2015-10-07 00:21:28 +02:00
|
|
|
/// Writes the combiner function for the alpha component for the specified TEV stage operation
|
2015-10-07 00:01:53 +02:00
|
|
|
static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation operation,
|
2015-10-06 04:33:47 +02:00
|
|
|
const std::string& variable_name) {
|
2015-10-13 04:23:26 +02:00
|
|
|
out += "clamp(";
|
2015-10-07 00:01:53 +02:00
|
|
|
using Operation = TevStageConfig::Operation;
|
2015-10-06 04:33:47 +02:00
|
|
|
switch (operation) {
|
|
|
|
case Operation::Replace:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += variable_name + "[0]";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Operation::Modulate:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += variable_name + "[0] * " + variable_name + "[1]";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Operation::Add:
|
2015-10-13 04:23:26 +02:00
|
|
|
out += variable_name + "[0] + " + variable_name + "[1]";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Operation::AddSigned:
|
2015-10-13 04:23:26 +02:00
|
|
|
out += variable_name + "[0] + " + variable_name + "[1] - 0.5";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Operation::Lerp:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (1.0 - " + variable_name + "[2])";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Operation::Subtract:
|
2015-10-13 04:23:26 +02:00
|
|
|
out += variable_name + "[0] - " + variable_name + "[1]";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Operation::MultiplyThenAdd:
|
2015-10-13 04:23:26 +02:00
|
|
|
out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case Operation::AddThenMultiply:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name + "[2]";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
default:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "0.0";
|
|
|
|
LOG_CRITICAL(Render_OpenGL, "Unknown alpha combiner operation: %u", operation);
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
}
|
2015-10-13 04:23:26 +02:00
|
|
|
out += ", 0.0, 1.0)";
|
2015-10-06 04:33:47 +02:00
|
|
|
}
|
|
|
|
|
2015-10-07 00:21:28 +02:00
|
|
|
/// Writes the if-statement condition used to evaluate alpha testing
|
2015-10-07 00:01:53 +02:00
|
|
|
static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) {
|
|
|
|
using CompareFunc = Regs::CompareFunc;
|
2015-10-06 04:33:47 +02:00
|
|
|
switch (func) {
|
|
|
|
case CompareFunc::Never:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "true";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case CompareFunc::Always:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "false";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
|
|
|
case CompareFunc::Equal:
|
|
|
|
case CompareFunc::NotEqual:
|
|
|
|
case CompareFunc::LessThan:
|
|
|
|
case CompareFunc::LessThanOrEqual:
|
|
|
|
case CompareFunc::GreaterThan:
|
|
|
|
case CompareFunc::GreaterThanOrEqual:
|
2015-10-21 06:04:02 +02:00
|
|
|
{
|
|
|
|
static const char* op[] = { "!=", "==", ">=", ">", "<=", "<", };
|
|
|
|
unsigned index = (unsigned)func - (unsigned)CompareFunc::Equal;
|
|
|
|
out += "int(last_tex_env_out.a * 255.0f) " + std::string(op[index]) + " alphatest_ref";
|
2015-10-06 04:33:47 +02:00
|
|
|
break;
|
2015-10-21 06:04:02 +02:00
|
|
|
}
|
|
|
|
|
2015-10-06 04:33:47 +02:00
|
|
|
default:
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "false";
|
2015-10-06 04:33:47 +02:00
|
|
|
LOG_CRITICAL(Render_OpenGL, "Unknown alpha test condition %u", func);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-07 00:21:28 +02:00
|
|
|
/// Writes the code to emulate the specified TEV stage
|
2015-10-10 04:46:47 +02:00
|
|
|
static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) {
|
2016-05-01 23:28:39 +02:00
|
|
|
const auto stage = static_cast<const Pica::Regs::TevStageConfig>(config.state.tev_stages[index]);
|
2015-10-07 00:01:53 +02:00
|
|
|
if (!IsPassThroughTevStage(stage)) {
|
|
|
|
std::string index_name = std::to_string(index);
|
|
|
|
|
|
|
|
out += "vec3 color_results_" + index_name + "[3] = vec3[3](";
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendColorModifier(out, config, stage.color_modifier1, stage.color_source1, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ", ";
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendColorModifier(out, config, stage.color_modifier2, stage.color_source2, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ", ";
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendColorModifier(out, config, stage.color_modifier3, stage.color_source3, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ");\n";
|
|
|
|
|
|
|
|
out += "vec3 color_output_" + index_name + " = ";
|
|
|
|
AppendColorCombiner(out, stage.color_op, "color_results_" + index_name);
|
|
|
|
out += ";\n";
|
|
|
|
|
|
|
|
out += "float alpha_results_" + index_name + "[3] = float[3](";
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendAlphaModifier(out, config, stage.alpha_modifier1, stage.alpha_source1, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ", ";
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendAlphaModifier(out, config, stage.alpha_modifier2, stage.alpha_source2, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ", ";
|
2016-04-19 00:53:42 +02:00
|
|
|
AppendAlphaModifier(out, config, stage.alpha_modifier3, stage.alpha_source3, index_name);
|
2015-10-07 00:01:53 +02:00
|
|
|
out += ");\n";
|
|
|
|
|
|
|
|
out += "float alpha_output_" + index_name + " = ";
|
|
|
|
AppendAlphaCombiner(out, stage.alpha_op, "alpha_results_" + index_name);
|
|
|
|
out += ";\n";
|
|
|
|
|
2015-10-13 04:23:26 +02:00
|
|
|
out += "last_tex_env_out = vec4("
|
|
|
|
"clamp(color_output_" + index_name + " * " + std::to_string(stage.GetColorMultiplier()) + ".0, vec3(0.0), vec3(1.0)),"
|
2015-10-08 03:01:28 +02:00
|
|
|
"clamp(alpha_output_" + index_name + " * " + std::to_string(stage.GetAlphaMultiplier()) + ".0, 0.0, 1.0));\n";
|
2015-10-07 00:01:53 +02:00
|
|
|
}
|
|
|
|
|
2015-12-01 07:33:38 +01:00
|
|
|
out += "combiner_buffer = next_combiner_buffer;\n";
|
|
|
|
|
2015-10-07 00:01:53 +02:00
|
|
|
if (config.TevStageUpdatesCombinerBufferColor(index))
|
2015-12-01 07:33:38 +01:00
|
|
|
out += "next_combiner_buffer.rgb = last_tex_env_out.rgb;\n";
|
2015-10-07 00:01:53 +02:00
|
|
|
|
|
|
|
if (config.TevStageUpdatesCombinerBufferAlpha(index))
|
2015-12-01 07:33:38 +01:00
|
|
|
out += "next_combiner_buffer.a = last_tex_env_out.a;\n";
|
2015-10-07 00:01:53 +02:00
|
|
|
}
|
|
|
|
|
2015-11-19 04:36:01 +01:00
|
|
|
/// Writes the code to emulate fragment lighting
|
|
|
|
static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
|
2016-05-01 23:28:39 +02:00
|
|
|
const auto& lighting = config.state.lighting;
|
|
|
|
|
2015-11-19 04:36:01 +01:00
|
|
|
// Define lighting globals
|
2015-11-26 02:25:02 +01:00
|
|
|
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"
|
|
|
|
"vec3 light_vector = vec3(0.0);\n"
|
|
|
|
"vec3 refl_value = vec3(0.0);\n";
|
2015-11-19 04:36:01 +01:00
|
|
|
|
2015-11-26 02:49:48 +01:00
|
|
|
// Compute fragment normals
|
2016-05-01 23:28:39 +02:00
|
|
|
if (lighting.bump_mode == Pica::Regs::LightingBumpMode::NormalMap) {
|
2015-11-26 02:49:48 +01:00
|
|
|
// Bump mapping is enabled using a normal map, read perturbation vector from the selected texture
|
2016-05-01 23:28:39 +02:00
|
|
|
std::string bump_selector = std::to_string(lighting.bump_selector);
|
2015-11-26 02:49:48 +01:00
|
|
|
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
|
2016-05-01 23:28:39 +02:00
|
|
|
if (lighting.bump_renorm) {
|
2015-11-26 02:49:48 +01:00
|
|
|
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";
|
|
|
|
}
|
2016-05-01 23:28:39 +02:00
|
|
|
} else if (lighting.bump_mode == Pica::Regs::LightingBumpMode::TangentMap) {
|
2015-11-26 02:49:48 +01:00
|
|
|
// Bump mapping is enabled using a tangent map
|
|
|
|
LOG_CRITICAL(HW_GPU, "unimplemented bump mapping mode (tangent mapping)");
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
} else {
|
|
|
|
// No bump mapping - surface local normal is just a unit normal
|
|
|
|
out += "vec3 surface_normal = vec3(0.0, 0.0, 1.0);\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Rotate the surface-local normal by the interpolated normal quaternion to convert it to eyespace
|
|
|
|
out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n";
|
2015-11-19 04:36:01 +01:00
|
|
|
|
|
|
|
// Gets the index into the specified lookup table for specular lighting
|
2016-05-01 23:28:39 +02:00
|
|
|
auto GetLutIndex = [&lighting](unsigned light_num, Regs::LightingLutInput input, bool abs) {
|
2015-11-19 04:36:01 +01:00
|
|
|
const std::string half_angle = "normalize(normalize(view) + light_vector)";
|
|
|
|
std::string index;
|
|
|
|
switch (input) {
|
|
|
|
case Regs::LightingLutInput::NH:
|
|
|
|
index = "dot(normal, " + half_angle + ")";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Regs::LightingLutInput::VH:
|
2015-11-25 04:59:14 +01:00
|
|
|
index = std::string("dot(normalize(view), " + half_angle + ")");
|
2015-11-19 04:36:01 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Regs::LightingLutInput::NV:
|
2015-11-25 04:59:14 +01:00
|
|
|
index = std::string("dot(normal, normalize(view))");
|
2015-11-19 04:36:01 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Regs::LightingLutInput::LN:
|
|
|
|
index = std::string("dot(light_vector, normal)");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %d\n", (int)input);
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (abs) {
|
|
|
|
// LUT index is in the range of (0.0, 1.0)
|
2016-05-01 23:28:39 +02:00
|
|
|
index = lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)";
|
2015-11-26 02:30:27 +01:00
|
|
|
return "(FLOAT_255 * clamp(" + index + ", 0.0, 1.0))";
|
2015-11-19 04:36:01 +01:00
|
|
|
} else {
|
|
|
|
// LUT index is in the range of (-1.0, 1.0)
|
|
|
|
index = "clamp(" + index + ", -1.0, 1.0)";
|
2015-11-26 02:30:27 +01:00
|
|
|
return "(FLOAT_255 * ((" + index + " < 0) ? " + index + " + 2.0 : " + index + ") / 2.0)";
|
2015-11-19 04:36:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return std::string();
|
|
|
|
};
|
|
|
|
|
|
|
|
// Gets the lighting lookup table value given the specified sampler and index
|
|
|
|
auto GetLutValue = [](Regs::LightingSampler sampler, std::string lut_index) {
|
|
|
|
return std::string("texture(lut[" + std::to_string((unsigned)sampler / 4) + "], " +
|
|
|
|
lut_index + ")[" + std::to_string((unsigned)sampler & 3) + "]");
|
|
|
|
};
|
|
|
|
|
|
|
|
// Write the code to emulate each enabled light
|
2016-05-01 23:28:39 +02:00
|
|
|
for (unsigned light_index = 0; light_index < lighting.src_num; ++light_index) {
|
|
|
|
const auto& light_config = lighting.light[light_index];
|
2015-11-19 05:40:18 +01:00
|
|
|
std::string light_src = "light_src[" + std::to_string(light_config.num) + "]";
|
2015-11-19 04:36:01 +01:00
|
|
|
|
|
|
|
// Compute light vector (directional or positional)
|
|
|
|
if (light_config.directional)
|
|
|
|
out += "light_vector = normalize(" + light_src + ".position);\n";
|
|
|
|
else
|
|
|
|
out += "light_vector = normalize(" + light_src + ".position + view);\n";
|
|
|
|
|
|
|
|
// Compute dot product of light_vector and normal, adjust if lighting is one-sided or two-sided
|
|
|
|
std::string dot_product = light_config.two_sided_diffuse ? "abs(dot(light_vector, normal))" : "max(dot(light_vector, normal), 0.0)";
|
|
|
|
|
|
|
|
// If enabled, compute distance attenuation value
|
|
|
|
std::string dist_atten = "1.0";
|
2015-11-19 05:40:18 +01:00
|
|
|
if (light_config.dist_atten_enable) {
|
2016-05-23 22:53:53 +02:00
|
|
|
std::string index = "(" + light_src + ".dist_atten_scale * length(-view - " + light_src + ".position) + " + light_src + ".dist_atten_bias)";
|
2015-11-26 02:25:02 +01:00
|
|
|
index = "((clamp(" + index + ", 0.0, FLOAT_255)))";
|
2015-11-19 05:40:18 +01:00
|
|
|
const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + light_config.num);
|
2015-11-26 02:25:02 +01:00
|
|
|
dist_atten = GetLutValue((Regs::LightingSampler)lut_num, index);
|
2015-11-19 04:36:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// If enabled, clamp specular component if lighting result is negative
|
2016-05-01 23:28:39 +02:00
|
|
|
std::string clamp_highlights = lighting.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0";
|
2015-11-19 04:36:01 +01:00
|
|
|
|
2015-11-20 04:42:06 +01:00
|
|
|
// Specular 0 component
|
2015-11-19 05:40:18 +01:00
|
|
|
std::string d0_lut_value = "1.0";
|
2016-05-01 23:28:39 +02:00
|
|
|
if (lighting.lut_d0.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Distribution0)) {
|
2015-11-20 04:42:06 +01:00
|
|
|
// Lookup specular "distribution 0" LUT value
|
2016-05-01 23:28:39 +02:00
|
|
|
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) + ")";
|
2015-11-19 05:40:18 +01:00
|
|
|
}
|
2015-11-20 04:42:06 +01:00
|
|
|
std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)";
|
|
|
|
|
2015-11-26 02:25:02 +01:00
|
|
|
// If enabled, lookup ReflectRed value, otherwise, 1.0 is used
|
2016-05-01 23:28:39 +02:00
|
|
|
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) + ")";
|
2015-11-26 02:25:02 +01:00
|
|
|
out += "refl_value.r = " + value + ";\n";
|
|
|
|
} else {
|
|
|
|
out += "refl_value.r = 1.0;\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
// If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used
|
2016-05-01 23:28:39 +02:00
|
|
|
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) + ")";
|
2015-11-26 02:25:02 +01:00
|
|
|
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
|
2016-05-01 23:28:39 +02:00
|
|
|
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) + ")";
|
2015-11-26 02:25:02 +01:00
|
|
|
out += "refl_value.b = " + value + ";\n";
|
|
|
|
} else {
|
|
|
|
out += "refl_value.b = refl_value.r;\n";
|
|
|
|
}
|
|
|
|
|
2015-11-20 04:42:06 +01:00
|
|
|
// Specular 1 component
|
|
|
|
std::string d1_lut_value = "1.0";
|
2016-05-01 23:28:39 +02:00
|
|
|
if (lighting.lut_d1.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Distribution1)) {
|
2015-11-20 04:42:06 +01:00
|
|
|
// Lookup specular "distribution 1" LUT value
|
2016-05-01 23:28:39 +02:00
|
|
|
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) + ")";
|
2015-11-20 04:42:06 +01:00
|
|
|
}
|
2015-11-26 02:25:02 +01:00
|
|
|
std::string specular_1 = "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)";
|
2015-11-19 04:36:01 +01:00
|
|
|
|
2015-11-24 02:26:09 +01:00
|
|
|
// Fresnel
|
2016-05-01 23:28:39 +02:00
|
|
|
if (lighting.lut_fr.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Fresnel)) {
|
2015-11-24 02:26:09 +01:00
|
|
|
// Lookup fresnel LUT value
|
2016-05-01 23:28:39 +02:00
|
|
|
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) + ")";
|
2015-11-24 02:26:09 +01:00
|
|
|
|
|
|
|
// Enabled for difffuse lighting alpha component
|
2016-05-01 23:28:39 +02:00
|
|
|
if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha ||
|
|
|
|
lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both)
|
2015-11-26 02:25:02 +01:00
|
|
|
out += "diffuse_sum.a *= " + value + ";\n";
|
2015-11-24 02:26:09 +01:00
|
|
|
|
|
|
|
// Enabled for the specular lighting alpha component
|
2016-05-01 23:28:39 +02:00
|
|
|
if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::SecondaryAlpha ||
|
|
|
|
lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both)
|
2015-11-26 02:25:02 +01:00
|
|
|
out += "specular_sum.a *= " + value + ";\n";
|
2015-11-24 02:26:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Compute primary fragment color (diffuse lighting) function
|
|
|
|
out += "diffuse_sum.rgb += ((" + light_src + ".diffuse * " + dot_product + ") + " + light_src + ".ambient) * " + dist_atten + ";\n";
|
|
|
|
|
2015-11-19 04:36:01 +01:00
|
|
|
// Compute secondary fragment color (specular lighting) function
|
2015-11-24 02:26:09 +01:00
|
|
|
out += "specular_sum.rgb += (" + specular_0 + " + " + specular_1 + ") * " + clamp_highlights + " * " + dist_atten + ";\n";
|
2015-11-19 04:36:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Sum final lighting result
|
2015-11-24 02:26:09 +01:00
|
|
|
out += "diffuse_sum.rgb += lighting_global_ambient;\n";
|
|
|
|
out += "primary_fragment_color = clamp(diffuse_sum, vec4(0.0), vec4(1.0));\n";
|
|
|
|
out += "secondary_fragment_color = clamp(specular_sum, vec4(0.0), vec4(1.0));\n";
|
2015-11-19 04:36:01 +01:00
|
|
|
}
|
|
|
|
|
2015-10-10 04:46:47 +02:00
|
|
|
std::string GenerateFragmentShader(const PicaShaderConfig& config) {
|
2016-05-01 23:28:39 +02:00
|
|
|
const auto& state = config.state;
|
|
|
|
|
2015-10-07 00:01:53 +02:00
|
|
|
std::string out = R"(
|
2015-11-26 04:33:24 +01:00
|
|
|
#version 330 core
|
2015-10-06 04:33:47 +02:00
|
|
|
#define NUM_TEV_STAGES 6
|
2015-11-12 23:33:21 +01:00
|
|
|
#define NUM_LIGHTS 8
|
2015-11-14 04:52:20 +01:00
|
|
|
#define LIGHTING_LUT_SIZE 256
|
2015-11-26 02:30:27 +01:00
|
|
|
#define FLOAT_255 (255.0 / 256.0)
|
2015-10-06 04:33:47 +02:00
|
|
|
|
2015-10-13 04:23:26 +02:00
|
|
|
in vec4 primary_color;
|
|
|
|
in vec2 texcoord[3];
|
2016-04-19 00:53:42 +02:00
|
|
|
in float texcoord0_w;
|
2015-11-12 23:33:21 +01:00
|
|
|
in vec4 normquat;
|
|
|
|
in vec3 view;
|
2015-10-13 04:23:26 +02:00
|
|
|
|
2015-10-06 04:33:47 +02:00
|
|
|
out vec4 color;
|
2015-11-10 17:58:53 +01:00
|
|
|
|
2015-11-12 23:33:21 +01:00
|
|
|
struct LightSrc {
|
2015-11-15 05:23:08 +01:00
|
|
|
vec3 specular_0;
|
|
|
|
vec3 specular_1;
|
2015-11-12 23:33:21 +01:00
|
|
|
vec3 diffuse;
|
|
|
|
vec3 ambient;
|
|
|
|
vec3 position;
|
2016-05-23 22:53:53 +02:00
|
|
|
float dist_atten_bias;
|
|
|
|
float dist_atten_scale;
|
2015-11-12 23:33:21 +01:00
|
|
|
};
|
|
|
|
|
2015-11-10 17:58:53 +01:00
|
|
|
layout (std140) uniform shader_data {
|
|
|
|
int alphatest_ref;
|
2016-03-30 19:27:04 +02:00
|
|
|
float depth_scale;
|
2016-01-04 00:46:54 +01:00
|
|
|
float depth_offset;
|
2015-11-12 23:33:21 +01:00
|
|
|
vec3 lighting_global_ambient;
|
|
|
|
LightSrc light_src[NUM_LIGHTS];
|
2016-05-23 16:03:11 +02:00
|
|
|
vec4 const_color[NUM_TEV_STAGES];
|
|
|
|
vec4 tev_combiner_buffer_color;
|
2015-11-10 17:58:53 +01:00
|
|
|
};
|
|
|
|
|
2015-12-01 07:33:38 +01:00
|
|
|
uniform sampler2D tex[3];
|
2015-11-15 23:43:01 +01:00
|
|
|
uniform sampler1D lut[6];
|
2015-10-06 04:33:47 +02:00
|
|
|
|
2015-11-26 02:49:48 +01:00
|
|
|
// Rotate the vector v by the quaternion q
|
|
|
|
vec3 quaternion_rotate(vec4 q, vec3 v) {
|
|
|
|
return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v);
|
|
|
|
}
|
|
|
|
|
2015-12-01 07:33:38 +01:00
|
|
|
void main() {
|
2015-11-12 23:33:21 +01:00
|
|
|
vec4 primary_fragment_color = vec4(0.0);
|
2015-11-15 05:23:08 +01:00
|
|
|
vec4 secondary_fragment_color = vec4(0.0);
|
2015-12-01 07:33:38 +01:00
|
|
|
)";
|
2015-10-06 04:33:47 +02:00
|
|
|
|
|
|
|
// Do not do any sort of processing if it's obvious we're not going to pass the alpha test
|
2016-05-01 23:28:39 +02:00
|
|
|
if (state.alpha_test_func == Regs::CompareFunc::Never) {
|
2015-10-08 03:11:32 +02:00
|
|
|
out += "discard; }";
|
2015-10-07 00:01:53 +02:00
|
|
|
return out;
|
2015-10-06 04:33:47 +02:00
|
|
|
}
|
|
|
|
|
2016-05-01 23:28:39 +02:00
|
|
|
if (state.lighting.enable)
|
2015-11-19 05:40:18 +01:00
|
|
|
WriteLighting(out, config);
|
|
|
|
|
2015-12-01 07:33:38 +01:00
|
|
|
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";
|
|
|
|
|
2016-05-01 23:28:39 +02:00
|
|
|
for (size_t index = 0; index < state.tev_stages.size(); ++index)
|
2015-10-07 00:01:53 +02:00
|
|
|
WriteTevStage(out, config, (unsigned)index);
|
2015-10-06 04:33:47 +02:00
|
|
|
|
2016-05-01 23:28:39 +02:00
|
|
|
if (state.alpha_test_func != Regs::CompareFunc::Always) {
|
2015-10-07 00:01:53 +02:00
|
|
|
out += "if (";
|
2016-05-01 23:28:39 +02:00
|
|
|
AppendAlphaTestCondition(out, state.alpha_test_func);
|
2015-10-13 04:23:26 +02:00
|
|
|
out += ") discard;\n";
|
2015-10-06 04:33:47 +02:00
|
|
|
}
|
|
|
|
|
2016-01-04 00:46:54 +01:00
|
|
|
out += "color = last_tex_env_out;\n";
|
2016-03-30 19:27:04 +02:00
|
|
|
|
|
|
|
out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n";
|
|
|
|
out += "float depth = z_over_w * depth_scale + depth_offset;\n";
|
|
|
|
if (state.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) {
|
|
|
|
out += "depth /= gl_FragCoord.w;\n";
|
|
|
|
}
|
|
|
|
out += "gl_FragDepth = depth;\n";
|
|
|
|
|
|
|
|
out += "}";
|
2015-10-07 00:01:53 +02:00
|
|
|
|
|
|
|
return out;
|
2015-10-06 04:33:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string GenerateVertexShader() {
|
2015-11-26 04:33:24 +01:00
|
|
|
std::string out = "#version 330 core\n";
|
2015-11-12 23:33:21 +01:00
|
|
|
|
2016-04-19 00:53:42 +02:00
|
|
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + ") in vec4 vert_position;\n";
|
|
|
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n";
|
|
|
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) + ") in vec2 vert_texcoord0;\n";
|
|
|
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) + ") in vec2 vert_texcoord1;\n";
|
|
|
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) + ") in vec2 vert_texcoord2;\n";
|
|
|
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0_W) + ") in float vert_texcoord0_w;\n";
|
|
|
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_NORMQUAT) + ") in vec4 vert_normquat;\n";
|
|
|
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_VIEW) + ") in vec3 vert_view;\n";
|
2015-10-22 03:50:55 +02:00
|
|
|
|
|
|
|
out += R"(
|
2015-10-13 04:23:26 +02:00
|
|
|
out vec4 primary_color;
|
|
|
|
out vec2 texcoord[3];
|
2016-04-19 00:53:42 +02:00
|
|
|
out float texcoord0_w;
|
2015-11-12 23:33:21 +01:00
|
|
|
out vec4 normquat;
|
|
|
|
out vec3 view;
|
2015-10-06 04:33:47 +02:00
|
|
|
|
|
|
|
void main() {
|
2015-10-13 04:23:26 +02:00
|
|
|
primary_color = vert_color;
|
|
|
|
texcoord[0] = vert_texcoord0;
|
|
|
|
texcoord[1] = vert_texcoord1;
|
|
|
|
texcoord[2] = vert_texcoord2;
|
2016-04-19 00:53:42 +02:00
|
|
|
texcoord0_w = vert_texcoord0_w;
|
2015-11-12 23:33:21 +01:00
|
|
|
normquat = vert_normquat;
|
|
|
|
view = vert_view;
|
2015-12-05 07:23:39 +01:00
|
|
|
gl_Position = vec4(vert_position.x, vert_position.y, -vert_position.z, vert_position.w);
|
2015-10-06 04:33:47 +02:00
|
|
|
}
|
|
|
|
)";
|
2015-10-22 03:50:55 +02:00
|
|
|
|
2015-10-07 00:01:53 +02:00
|
|
|
return out;
|
2015-10-06 04:33:47 +02:00
|
|
|
}
|
|
|
|
|
2015-10-07 00:01:53 +02:00
|
|
|
} // namespace GLShader
|