Files
Webcam/include/engine/gpu/gpu_post_process_chain.cpp

669 lines
22 KiB
C++

/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include <math.h>
#include "gpu/gpu_renderer.h"
#include "gpu/gpu_geometry.h"
#include "gpu/gpu_shader_object.h"
#include "gpu/gpu_draw_context.h"
#include "core/geometry.h"
#include "rand/rand.h"
#include "log/log.h"
using namespace GS;
using namespace GPU;
//------------------------------------------------------------------------------
static bool IsPostProcessExcluded(NML::Tag *exclusion_key, const char *tag)
{
NML::Tag *__t = exclusion_key ? exclusion_key->GetTypedTag(tag, Variant::VariantBool) : NULL;
return __t && __t->GetBool();
}
//------------------------------------------------------------------------------
//---------------------------------------------------------------
#define _SwapTarget { tmp = t[0]; t[0] = t[1]; t[1] = tmp; }
//---------------------------------------------------------------
//------------------------------------------------------------------------------
void Renderer::GetPostProcessNormalDepth(const Stack <RenderPrimitive *> display_lists[2])
{
if (normal_depth_updated)
return;
ScopedPerfEvent event(this, __FUNCTION__, Color::Purple);
fRect old_viewport = GetViewport();
// Generate normal/depth buffer.
SetViewport(fRect(0, 0, (float)t_fx[2]->GetWidth(), (float)t_fx[2]->GetHeight()));
fx_fbo->SetColorTexture(t_fx[2]);
if (render_technique == TechniqueDeferred)
{
SetCurrentFBO(fx_fbo);
RenderFullscreenQuad(*single_texture_program, old_viewport.GetWidth() / (float)dimensions.x, old_viewport.GetHeight() / (float)dimensions.y, t_gbuffer[0]);
}
else
{
fx_fbo->SetDepthTexture(t_fx_depth);
SetCurrentFBO(fx_fbo);
Clear(0, 0, 0);
DrawContext dc(DrawContext::Opaque, DrawContext::Base, MaterialShader::PP_NormalDepth);
DrawList(display_lists[0], dc);
fx_fbo->SetDepthTexture(NULL);
}
SetViewport(old_viewport);
normal_depth_updated = true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Renderer::ApplyDirectionalBlur(Render::Texture *t[2], const Vector2 &d, float attn)
{
if (!fx_blur_program)
return;
Render::Texture *tmp;
ShaderInput *u_pass = fx_blur_program->GetInput("u_pass"),
*u_blur_d = fx_blur_program->GetInput("u_blur_d"),
*u_attenuation = fx_blur_program->GetInput("u_attenuation");
SetShaderProgram(fx_blur_program);
u_blur_d->SetValue(d.x, d.y);
u_attenuation->SetValue(attn);
fRect nviewport(viewport.sx / dimensions.x, viewport.sy / dimensions.y, viewport.ex / dimensions.x, viewport.ey / dimensions.y);
for (int n = 0; n < 4; ++n)
{
fx_fbo->SetColorTexture(t[1]);
SetCurrentFBO(fx_fbo);
u_pass->SetValue(float(n));
RenderFullscreenQuad(*fx_blur_program, nviewport, fRect(0, 0, 1, 1), t[0]);
_SwapTarget
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Renderer::ApplyBloomFilter(Render::Texture *t_in, float strength, float threshold, float exponent, float radius, float strength_white_screen)
{
if (!strength || !single_texture_cutoff_program || !tone_mapping_program)
return;
ScopedPerfEvent event(this, __FUNCTION__, Color::Purple);
Render::Texture *t[] = { t_fx[0], t_fx[1] };
ShaderInput *u_cutoff = single_texture_cutoff_program->GetInput("u_cutoff"),
*u_strength = tone_mapping_program->GetInput("u_strength"),
*u_strength_white_screen = tone_mapping_program->GetInput("u_strength_white_screen");
if (!u_cutoff || !u_strength || !u_strength_white_screen)
return;
fRect old_viewport = GetViewport();
fRect nviewport(viewport.sx / dimensions.x, viewport.sy / dimensions.y, viewport.ex / dimensions.x, viewport.ey / dimensions.y);
fRect fx_viewport(old_viewport.sx / fx_scale, old_viewport.sy / fx_scale, old_viewport.ex / fx_scale, old_viewport.ey / fx_scale);
//--------------------------------------------------------------------------
#define CutoffFrameToBloomFX \
{ \
SetViewport(fx_viewport); \
\
fx_fbo->SetColorTexture(t[0]); \
SetCurrentFBO(fx_fbo);\
SetShaderProgram(single_texture_cutoff_program); \
u_cutoff->SetValue(threshold); \
RenderFullscreenQuad(*single_texture_cutoff_program, nviewport, fRect(0, 0, 1, 1), t_in); \
}
#define OutputBloomFXToFrame \
{ \
SetViewport(old_viewport);\
\
EnableBlending(true); \
SetBlendFunc(BlendOne, BlendOne); \
\
fx_fbo->SetColorTexture(t_in); \
SetCurrentFBO(fx_fbo);\
SetShaderProgram(tone_mapping_program); \
u_strength->SetValue(strength * 1.25f); \
u_strength_white_screen->SetValue(strength_white_screen); \
RenderFullscreenQuad(*tone_mapping_program, nviewport, fRect(0, 0, 1, 1), t[0]); \
\
EnableBlending(false); \
}
//--------------------------------------------------------------------------
if (view_registry->GetBool("PostProcess:Bloom:Streak:Enabled", false))
{
float angle = view_registry->GetReal("PostProcess:Bloom:Streak:Angle"),
attn = view_registry->GetReal("PostProcess:Bloom:Streak:Attenuation", 0.975f);
for (int n = 0; n < 2; ++n)
{
Vector2 d = Vector2(cos(angle), sin(angle)) * radius / 12.f;
CutoffFrameToBloomFX
ApplyDirectionalBlur(t, d, attn);
OutputBloomFXToFrame
if (!view_registry->GetBool("PostProcess:Bloom:Streak:CrossShaped", false))
break;
angle += Units::Deg(90.f);
}
}
else
{
CutoffFrameToBloomFX
ApplyDirectionalBlur(t, Vector2(radius / 64.f, 0));
ApplyDirectionalBlur(t, Vector2(0, radius / 64.f));
OutputBloomFXToFrame
}
SetViewport(old_viewport);
SetClippingRect(&old_viewport);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Renderer::ApplyNoiseFilter(Render::Texture *t_in, Render::Texture *t_out, float strength, float mono, float bias)
{
if (!strength || !noise_program)
return false;
ScopedPerfEvent event(this, __FUNCTION__, Color::Purple);
ShaderInput *u_strength = noise_program->GetInput("u_strength"),
*u_mono = noise_program->GetInput("u_mono"),
*u_bias = noise_program->GetInput("u_bias"),
*u_random = noise_program->GetInput("u_random");
if (!u_strength || !u_mono || !u_bias || !u_random)
return false;
fx_fbo->SetColorTexture(t_out);
SetCurrentFBO(fx_fbo);
float random[2] = { Random::FRand(), Random::FRand() };
SetShaderProgram(noise_program);
u_strength->SetValue(strength);
u_mono->SetValue(mono);
u_bias->SetValue(bias);
u_random->SetValue(random[0], random[1]);
RenderFullscreenQuad(*noise_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_in);
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Renderer::ApplySSAAFilter(Render::Texture *t_in, Render::Texture *t_out)
{
if (!ssaa_program)
return false;
ScopedPerfEvent event(this, __FUNCTION__, Color::Purple);
fx_fbo->SetColorTexture(t_out);
SetCurrentFBO(fx_fbo);
SetShaderProgram(ssaa_program);
RenderFullscreenQuad(*ssaa_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_in);
return true;
}
//------------------------------------------------------------------------------
bool Renderer::ApplyResolveMSAADepth(Render::Texture *t_depth_msaa, Render::Texture *t_out)
{
if (!t_depth_msaa || !t_out || !resolve_msaa_depth_program)
return false;
ScopedPerfEvent event(this, __FUNCTION__, Color::Purple);
fx_fbo->SetColorTexture(t_out);
SetCurrentFBO(fx_fbo);
ShaderInput *msaa_depth = resolve_msaa_depth_program->GetInput("u_depthMSAA");
SetShaderProgram(resolve_msaa_depth_program);
msaa_depth->SetValue(t_depth_msaa);
RenderFullscreenQuad(*resolve_msaa_depth_program,viewport.GetWidth() / (float)dimensions.x,viewport.GetHeight() / (float)dimensions.y);
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Renderer::ApplySSAOFilter(Render::Texture *t_in, Render::Texture *t_out, const Stack <RenderPrimitive *> display_lists[2], float s, float r, float d, float blur_r)
{
if (!s || !ssao_program)
return false;
ScopedPerfEvent event(this, __FUNCTION__, Color::Purple);
ShaderInput *u_strength = ssao_program->GetInput("u_strength"),
*u_radius = ssao_program->GetInput("u_radius"),
*u_distance_scale = ssao_program->GetInput("u_distance_scale"),
*u_iproj2d = ssao_program->GetInput("u_iproj2d");
if (!u_strength || !u_radius || !u_distance_scale)
return false;
GetPostProcessNormalDepth(display_lists);
#if 0
// Normal/depth debug output.
fx_fbo->SetColorTexture(t_in);
SetCurrentFBO(fx_fbo);
RenderFullscreenQuad(single_texture_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_fx[2]);
return false;
#endif
fRect old_viewport = GetViewport();
SetViewport(fRect(0, 0, (float)t_fx[2]->GetWidth(), (float)t_fx[2]->GetHeight()));
// Render raw SSAO to FX texture.
SetShaderProgram(ssao_program);
u_strength->SetValue(s);
u_radius->SetValue(r * (4 / fx_scale));
u_distance_scale->SetValue(d);
float iproj[] = { 1.f / m_projection.m[0][0], 1.f / m_projection.m[1][1] };
if (!gpu_config.tex_origin_is_top_left)
iproj[1] = -iproj[1];
u_iproj2d->SetValue(iproj[0], iproj[1]);
EnableAlphaTest(false);
EnableBlending(false);
int out_index = 0;
fx_fbo->SetColorTexture(t_fx[out_index]);
SetCurrentFBO(fx_fbo);
Clear(0, 0, 0, 0, 1, ClearColor); // FIXME this is USELESS, but something is killing fragments with 0 alpha in ssao_program and disabling alpha testing does not solves the issue.
RenderFullscreenQuad(*ssao_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_fx[2]);
if (ssao_blur_program)
{
// SSAO blur.
if (blur_r > 0.f)
{
ShaderInput *u_blur_radius = ssao_blur_program->GetInput("u_blur_radius"),
*u_normal_depth = ssao_blur_program->GetInput("u_normal_depth"); // the normal depth texture is not always used, depending on the quality settings.
if (u_blur_radius && u_normal_depth)
{
fx_fbo->SetColorTexture(t_fx[1 - out_index]);
SetCurrentFBO(fx_fbo);
Clear(0, 0, 0, 0, 1, ClearColor); // FIXME this is USELESS, but something is killing fragments with 0 alpha in ssao_program and disabling alpha testing does not solves the issue.
SetShaderProgram(ssao_blur_program);
u_blur_radius->SetValue(blur_r);
u_normal_depth->SetValue(t_fx[2].c_ptr());
RenderFullscreenQuad(*ssao_blur_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_fx[out_index]);
out_index = 1 - out_index;
}
}
}
// Composite back over input.
SetViewport(old_viewport);
fx_fbo->SetColorTexture(t_in);
SetCurrentFBO(fx_fbo);
EnableBlending(true);
SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha);
RenderFullscreenQuad(*single_texture_program, 1, 1, t_fx[out_index]);
EnableBlending(false);
return false;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Renderer::ApplySharpenFilter(Render::Texture *t_in, Render::Texture *t_out, float strength)
{
if (!strength || !sharpen_program)
return false;
ScopedPerfEvent event(this, __FUNCTION__, Color::Purple);
ShaderInput *u_strength = sharpen_program->GetInput("u_strength");
if (!u_strength)
return false;
fx_fbo->SetColorTexture(t_out);
SetCurrentFBO(fx_fbo);
SetShaderProgram(sharpen_program);
u_strength->SetValue(strength);
RenderFullscreenQuad(*sharpen_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_in);
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Renderer::ApplyHSL(Render::Texture *t_in, Render::Texture *t_out, float H, float S, float L)
{
if (((H == 1.f) && (S == 1.f) && (L == 1.f)) || !hsl_program)
return false;
ScopedPerfEvent event(this, __FUNCTION__, Color::Purple);
ShaderInput *u_H = hsl_program->GetInput("u_H"),
*u_S = hsl_program->GetInput("u_S"),
*u_L = hsl_program->GetInput("u_L");
if (!u_H || !u_S || !u_L)
return false;
fx_fbo->SetColorTexture(t_out);
SetCurrentFBO(fx_fbo);
SetShaderProgram(hsl_program);
u_H->SetValue(H);
u_S->SetValue(S);
u_L->SetValue(L);
RenderFullscreenQuad(*hsl_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_in);
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Renderer::ApplyChromaticDispersion(Render::Texture *t_in, Render::Texture *t_out, float width)
{
if ((width == 0.f) || !chromatic_dispersion_program)
return false;
ScopedPerfEvent event(this, __FUNCTION__, Color::Purple);
ShaderInput *u_width = chromatic_dispersion_program->GetInput("u_width");
if (!u_width)
return false;
fx_fbo->SetColorTexture(t_out);
SetCurrentFBO(fx_fbo);
SetShaderProgram(chromatic_dispersion_program);
u_width->SetValue(width);
RenderFullscreenQuad(*chromatic_dispersion_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_in);
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Renderer::ApplyRadialBlur(Render::Texture *t_in, Render::Texture *t_out, float strength, float center_x, float center_y)
{
if (!strength || !radial_blur_program)
return false;
ScopedPerfEvent event(this, __FUNCTION__, Color::Purple);
ShaderInput *u_strength = radial_blur_program->GetInput("u_strength"),
*u_center = radial_blur_program->GetInput("u_center");
if (!u_strength || !u_center)
return false;
fx_fbo->SetColorTexture(t_out);
SetCurrentFBO(fx_fbo);
SetShaderProgram(radial_blur_program);
u_strength->SetValue(strength);
float center[] = { center_x * viewport.GetWidth() / (float)dimensions.x, center_y * viewport.GetHeight() / (float)dimensions.y };
u_center->SetValue(center[0], center[1]);
RenderFullscreenQuad(*radial_blur_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y, t_in);
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Renderer::ApplyMotionBlur(Render::Texture *t_in, Render::Texture *t_out, const Stack <RenderPrimitive *> display_lists[2], float strength, int quality)
{
if (!strength || !quality || !motion_blur_program)
return false;
ScopedPerfEvent event(this, __FUNCTION__, Color::Purple);
float k_u = viewport.GetWidth() / dimensions.x, k_v = viewport.GetHeight() / dimensions.y;
// Generate a velocity buffer from the opaque surface list.
fRect old_viewport = GetViewport();
{
ScopedPerfEvent event(this, "Render Velocity Buffer", Color::Purple);
SetViewport(fRect(0, 0, (float)t_fx[0]->GetWidth(), (float)t_fx[0]->GetHeight()));
fx_fbo->SetColorTexture(t_fx[0]);
fx_fbo->SetDepthTexture(t_fx_depth);
SetCurrentFBO(fx_fbo);
Clear(0, 0, 0);
DrawContext dc(DrawContext::Opaque, DrawContext::Base, MaterialShader::PP_Velocity);
DrawList(display_lists[0], dc);
}
// Vector field blur.
#if 0
float k_blur = 0.5;
Render::Texture *t_pp_0[] = { t_fx[0], t_fx[1] };
ApplyDirectionalBlur(t_pp_0, nVector2(k_blur, 0), 0.975f);
Render::Texture *t_pp_1[] = { t_fx[1], t_fx[0] };
ApplyDirectionalBlur(t_pp_1, nVector2(0, k_blur), 0.975f);
#endif
// Apply velocity field.
fx_fbo->SetDepthTexture(NULL);
// Quality: 0 - No PP, 1 - Lores blur, 2 - Hires blur.
if (quality == 1)
{
fx_fbo->SetColorTexture(t_fx[1]);
SetCurrentFBO(fx_fbo);
SetShaderProgram(single_texture_program);
RenderFullscreenQuad(*single_texture_program, 1, 1, t_in);
}
else
{
fx_fbo->SetColorTexture(t_out);
SetCurrentFBO(fx_fbo);
SetViewport(old_viewport);
}
ShaderInput *u_strength = motion_blur_program->GetInput("u_strength"),
*u_pow = motion_blur_program->GetInput("u_pow"),
*u_max = motion_blur_program->GetInput("u_max"),
*u_source = motion_blur_program->GetInput("u_source"),
*u_velocity = motion_blur_program->GetInput("u_velocity");
SetShaderProgram(motion_blur_program);
const float k = 1.f; // stats.bench_fps.GetFps() / 60.f; // Normalize to 60fps.
u_strength->SetValue(strength * 32.f * k);
u_pow->SetValue(2.f);
u_max->SetValue(1.f / 128.f); // Works in normalized space, does not need to adjust for variable resolution.
motion_blur_program->Set(*u_velocity->location, *t_fx[0], u_velocity->index);
if (quality == 1) // low-res blur path
{
fx_fbo->SetColorTexture(t_fx[2]);
SetCurrentFBO(fx_fbo);
u_source->SetValue(t_fx[1].c_ptr());
RenderFullscreenQuad(*motion_blur_program, 1, 1);
fx_fbo->SetColorTexture(t_in);
SetCurrentFBO(fx_fbo);
SetViewport(old_viewport);
EnableBlending(true);
SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha);
SetShaderProgram(single_texture_program);
RenderFullscreenQuad(*single_texture_program, k_u, k_v, t_fx[2]);
EnableBlending(false);
return false;
}
u_source->SetValue(t_in);
RenderFullscreenQuad(*motion_blur_program, viewport.GetWidth() / (float)dimensions.x, viewport.GetHeight() / (float)dimensions.y);
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Render::Texture *Renderer::ApplyPostProcessChain(const Stack <RenderPrimitive *> display_lists[2])
{
ScopedBenchmark bench(stats.bench_post_process);
ScopedPerfEvent event(this, "Apply Post-Processing Chain", Color::Green);
if (!gpu_config.use_rtt)
return t_compose[0];
normal_depth_updated = false;
NML::Tag *post_process_registry = view_registry ? view_registry->GetTag("PostProcess") : NULL;
if (!post_process_registry)
return t_compose[0];
NML::Tag *exclusion_key = registry.GetTag("PostProcess:Exclusion");
fRect old_clipping = GetClippingRect();
SetClippingRect(NULL);
uint i_compose = 0;
NML::Tag *tag;
// SSAO.
#if !(__PLATFORM_ANDROID_NDK__ || __PLATFORM_IOS__)
if (((tag = post_process_registry->GetTag("SSAO")) != NULL) && !IsPostProcessExcluded(exclusion_key, "SSAO"))
if (ApplySSAOFilter
(
t_compose[i_compose],
t_compose[1 - i_compose],
display_lists,
view_registry->GetReal("PostProcess:SSAO:Strength", 1),
view_registry->GetReal("PostProcess:SSAO:Radius", 2),
view_registry->GetReal("PostProcess:SSAO:DistanceScale", 0.5),
view_registry->GetReal("PostProcess:SSAO:BlurRadius", 8)
))
i_compose = 1 - i_compose;
#endif
// Sharpen.
if (((tag = post_process_registry->GetTag("Sharpen")) != NULL) && !IsPostProcessExcluded(exclusion_key, "Sharpen"))
if (ApplySharpenFilter
(
t_compose[i_compose],
t_compose[1 - i_compose],
view_registry->GetReal("PostProcess:Sharpen:Strength", 0.5f)
))
i_compose = 1 - i_compose;
// SSAA.
if (render_technique == TechniqueDeferred)
if (registry.GetBool("Antialiasing:Enable", false))
if (ApplySSAAFilter
(
t_compose[i_compose],
t_compose[1 - i_compose]
))
i_compose = 1 - i_compose;
#if !(__PLATFORM_ANDROID_NDK__ || __PLATFORM_IOS__)
// Motion blur.
if (((tag = post_process_registry->GetTag("MotionBlur")) != NULL) && !IsPostProcessExcluded(exclusion_key, "MotionBlur"))
if (ApplyMotionBlur
(
t_compose[i_compose],
t_compose[1 - i_compose],
display_lists,
view_registry->GetReal("PostProcess:MotionBlur:Strength", 0.5),
registry.GetInteger("PostProcess:MotionBlur:Quality", 2)
))
i_compose = 1 - i_compose;
#endif
// Radial blur.
if (((tag = post_process_registry->GetTag("RadialBlur")) != NULL) && !IsPostProcessExcluded(exclusion_key, "RadialBlur"))
if (ApplyRadialBlur
(
t_compose[i_compose],
t_compose[1 - i_compose],
view_registry->GetReal("PostProcess:RadialBlur:Strength", 0.5),
view_registry->GetReal("PostProcess:RadialBlur:CenterX", 0.5),
view_registry->GetReal("PostProcess:RadialBlur:CenterY", 0.5)
))
i_compose = 1 - i_compose;
// Bloom.
if (((tag = post_process_registry->GetTag("Bloom")) != NULL) && !IsPostProcessExcluded(exclusion_key, "Bloom"))
ApplyBloomFilter
(
t_compose[i_compose],
view_registry->GetReal("PostProcess:Bloom:Strength", 1),
view_registry->GetReal("PostProcess:Bloom:Threshold", 0.95f),
view_registry->GetReal("PostProcess:Bloom:Exponent", 4),
view_registry->GetReal("PostProcess:Bloom:Radius", 12),
view_registry->GetReal("PostProcess:Sharpen:Strength", 0.5f)
);
// Noise.
#if !(__PLATFORM_ANDROID_NDK__ || __PLATFORM_IOS__)
// TODO mobile version of this.
if (((tag = post_process_registry->GetTag("Noise")) != NULL) && !IsPostProcessExcluded(exclusion_key, "Noise"))
if (ApplyNoiseFilter
(
t_compose[i_compose],
t_compose[1 - i_compose],
view_registry->GetReal("PostProcess:Noise:Strength", 0.25f),
view_registry->GetReal("PostProcess:Noise:Monochromatic", 0.f),
view_registry->GetReal("PostProcess:Noise:LumaBias", 0.5f)
) )
i_compose = 1 - i_compose;
#endif
// HSL.
if (((tag = post_process_registry->GetTag("HueSaturation")) != NULL) && !IsPostProcessExcluded(exclusion_key, "HueSaturation"))
if (ApplyHSL
(
t_compose[i_compose],
t_compose[1 - i_compose],
view_registry->GetReal("PostProcess:HueSaturation:H", 1),
view_registry->GetReal("PostProcess:HueSaturation:S", 1),
view_registry->GetReal("PostProcess:HueSaturation:L", 1)
) )
i_compose = 1 - i_compose;
// Chromatic dispersion.
if (((tag = post_process_registry->GetTag("ChromDisp")) != NULL) && !IsPostProcessExcluded(exclusion_key, "ChromDisp"))
if (ApplyChromaticDispersion
(
t_compose[i_compose],
t_compose[1 - i_compose],
view_registry->GetReal("PostProcess:ChromDisp:Width", 1)
) )
i_compose = 1 - i_compose;
SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha);
SetClippingRect(&old_clipping);
SetIndexSource(NULL);
SetVertexSource(NULL, 0);
return t_compose[i_compose];
}
//------------------------------------------------------------------------------