filter-blur: Add Linear Box Blur and combine all effects

Linear Box Blur abuses the fact that with Linear Sampling we can sample up to four adjacent texels at the same time and get a correct result for Box Blur back. Using this the total number of sample for Box Blur is reduced by n, making the total either n+1 (Even Radius) or n (Odd Radius).

Additionally all blur effect files have been merged into a single blur.effect file to reduce the time required to change a single parameter name. New blur effects should be added as a new technique instead of as a new effect file.

See Also: #21 Blur Quality
This commit is contained in:
Michael Fabian 'Xaymar' Dirks 2018-12-22 22:07:33 +01:00
parent 0ad73bbf67
commit 93df9b50b8
9 changed files with 253 additions and 318 deletions

View file

@ -184,7 +184,7 @@ ElseIf(${PropertyPrefix}OBS_DOWNLOAD)
) )
INCLUDE("${libobs_SOURCE_DIR}/cmake/LibObs/LibObsConfig.cmake") INCLUDE("${libobs_SOURCE_DIR}/cmake/LibObs/LibObsConfig.cmake")
Else() Else()
Message(CRITICAL "Impossible case reached, very system stability.") Message(CRITICAL "Impossible case reached, verify system stability.")
Return() Return()
EndIf() EndIf()
@ -195,15 +195,13 @@ SET(PROJECT_DATA_LOCALE
"${PROJECT_SOURCE_DIR}/data/locale/en-US.ini" "${PROJECT_SOURCE_DIR}/data/locale/en-US.ini"
) )
SET(PROJECT_DATA_EFFECTS SET(PROJECT_DATA_EFFECTS
"${PROJECT_SOURCE_DIR}/data/effects/bilateral-blur.effect" "${PROJECT_SOURCE_DIR}/data/effects/blur.effect"
"${PROJECT_SOURCE_DIR}/data/effects/box-blur.effect"
"${PROJECT_SOURCE_DIR}/data/effects/gaussian-blur.effect"
"${PROJECT_SOURCE_DIR}/data/effects/displace.effect"
"${PROJECT_SOURCE_DIR}/data/effects/color-conversion.effect" "${PROJECT_SOURCE_DIR}/data/effects/color-conversion.effect"
"${PROJECT_SOURCE_DIR}/data/effects/displace.effect"
"${PROJECT_SOURCE_DIR}/data/effects/mask.effect" "${PROJECT_SOURCE_DIR}/data/effects/mask.effect"
"${PROJECT_SOURCE_DIR}/data/effects/mip-mapper.effect"
"${PROJECT_SOURCE_DIR}/data/effects/mipgen.effect" "${PROJECT_SOURCE_DIR}/data/effects/mipgen.effect"
"${PROJECT_SOURCE_DIR}/data/effects/sdf-generator.effect" "${PROJECT_SOURCE_DIR}/data/effects/sdf-generator.effect"
"${PROJECT_SOURCE_DIR}/data/effects/sdf-shadow.effect"
) )
SET(PROJECT_DATA_SHADERS SET(PROJECT_DATA_SHADERS
# "${PROJECT_SOURCE_DIR}/data/shaders/name.effect" # "${PROJECT_SOURCE_DIR}/data/shaders/name.effect"

View file

@ -1,95 +0,0 @@
// OBS Default
uniform float4x4 ViewProj;
// Settings (Shared)
uniform texture2d u_image;
uniform float2 u_imageSize;
uniform float2 u_imageTexel;
uniform int u_radius;
uniform int u_diameter;
uniform float2 u_texelDelta;
// Settings (Private)
uniform float bilateralSmoothing;
uniform float bilateralSharpness;
sampler_state textureSampler {
Filter = Point;
AddressU = Clamp;
AddressV = Clamp;
MinLOD = 0;
MaxLOD = 0;
};
struct VertDataIn {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
struct VertDataOut {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
VertDataOut VSDefault(VertDataIn v_in)
{
VertDataOut vert_out;
vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj);
vert_out.uv = v_in.uv;
return vert_out;
}
// Bilateral Blur
float Bilateral(float x, float sigma) {
return 0.39894 * exp(-0.5 * (x*x) / (sigma*sigma)) / sigma;
}
float Bilateral3(float3 v, float sigma) {
// First part is Bilateral function (1.0 / (o * sqrt(2.0 * pivalue))) with o = 1
return 0.39894 * exp(-0.5 * dot(v,v) / (sigma*sigma)) / sigma;
}
float4 BlurFunc(float2 uv, float4 rgba) {
float2 uvOffset = float2(0, 0);
float Z = 0.0;
float bZ = 1.0 / Bilateral(0.0, bilateralSharpness);
float3 color = float3(0, 0, 0);
for (int k = 1; k <= u_radius; k++) {
uvOffset += u_texelDelta;
// Bilateral Kernel
float bKernel = Bilateral(abs(k), bilateralSmoothing);
bKernel *= bKernel;
float bZKernel = bZ * bKernel;
// Sample Color
float3 l_p = u_image.SampleLevel(textureSampler, uv + uvOffset, 0).rgb;
float3 l_n = u_image.SampleLevel(textureSampler, uv - uvOffset, 0).rgb;
// Bilateral Stuff
float l_factor_p = Bilateral3(l_p - rgba.rgb, bilateralSharpness) * bZKernel;
float l_factor_n = Bilateral3(l_n - rgba.rgb, bilateralSharpness) * bZKernel;
Z = Z + l_factor_p + l_factor_n;
// Store Color
color += l_p * l_factor_p;
color += l_n * l_factor_n;
}
return float4(color.rgb / Z, rgba.a);
}
float4 PSBilateral(VertDataOut v_in) : TARGET {
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
return BlurFunc(v_in.uv, rgba);
}
technique Draw
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSBilateral(v_in);
}
}

207
data/effects/blur.effect Normal file
View file

@ -0,0 +1,207 @@
// OBS Default
uniform float4x4 ViewProj;
// Settings (Shared)
uniform texture2d u_image;
uniform float2 u_imageSize;
uniform float2 u_imageTexel;
uniform int u_radius;
uniform int u_diameter;
uniform float2 u_texelDelta;
// Kernel Settings
//uniform float registerkernel[25];
uniform texture2d kernel;
uniform float2 kernelTexel;
// Bilateral Settings
uniform float bilateralSmoothing;
uniform float bilateralSharpness;
// Data
sampler_state pointSampler {
Filter = Point;
AddressU = Clamp;
AddressV = Clamp;
MinLOD = 0;
MaxLOD = 0;
};
sampler_state linearSampler {
Filter = Linear;
AddressU = Clamp;
AddressV = Clamp;
MinLOD = 0;
MaxLOD = 0;
};
struct VertDataIn {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
struct VertDataOut {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
VertDataOut VSDefault(VertDataIn vtx)
{
VertDataOut vert_out;
vert_out.pos = mul(float4(vtx.pos.xyz, 1.0), ViewProj);
vert_out.uv = vtx.uv;
return vert_out;
}
/// Blur: Box
float4 PSBoxBlur(VertDataOut vtx) : TARGET {
float4 origin = u_image.SampleLevel(pointSampler, vtx.uv, 0);
float4 final = origin;
for (int k = 1; k <= u_radius; k++) {
final += u_image.SampleLevel(pointSampler, vtx.uv + (u_texelDelta * k), 0);
final += u_image.SampleLevel(pointSampler, vtx.uv - (u_texelDelta * k), 0);
}
final /= u_diameter;
return final;
}
technique Box
{
pass
{
vertex_shader = VSDefault(vtx);
pixel_shader = PSBoxBlur(vtx);
}
}
/// Blur: Box (Linear Optimized)
// By abusing Linear sampling we can reduce the necessary samples, halving the total samples.
float4 PSBoxBlurLinear(VertDataOut vtx) : TARGET {
// Radius 4 (Even):
// [-4, -3, -2, -1, 0, +1, +2, +3, +4]
// ^-S-^ ^-S-^ S ^-S-^ ^-S-^
// Total Samples: 5 (n+1)
// Radius 3 (Odd):
// [-3, -2, -1, 0, +1, +2, +3]
// ^-S-^ ^-S-^ S ^-S-^
// Total Samples: 4 (n)
// Radius 2 (Even):
// [-2, -1, 0, +1, +2]
// ^-S-^ S ^-S-^
float4 final = float4(0, 0, 0, 0);
float2 halfTexelDelta = u_texelDelta / 2.0;
if (u_radius % 2 == 0) {
// Even Numbers require the origin sample in the middle.
float4 origin = u_image.SampleLevel(pointSampler, vtx.uv, 0);
final = origin;
for (int k = 1; k <= u_radius; k+=2) {
float2 offset = k * u_texelDelta + halfTexelDelta;
final += u_image.SampleLevel(linearSampler, vtx.uv + offset, 0) * 2;
final += u_image.SampleLevel(linearSampler, vtx.uv - offset, 0) * 2;
}
} else {
// Odd Numbers put the origin sample in another location.
float4 origin = u_image.SampleLevel(pointSampler, vtx.uv + u_texelDelta, 0);
float4 group = u_image.SampleLevel(linearSampler, vtx.uv - halfTexelDelta, 0);
final = origin + group * 2;
for (int k = 2; k <= u_radius; k+=2) {
float2 offset = k * u_texelDelta + halfTexelDelta;
final += u_image.SampleLevel(linearSampler, vtx.uv + offset, 0) * 2;
final += u_image.SampleLevel(linearSampler, vtx.uv - offset, 0) * 2;
}
}
final /= u_diameter;
return final;
}
technique BoxLinear
{
pass
{
vertex_shader = VSDefault(vtx);
pixel_shader = PSBoxBlurLinear(vtx);
}
}
/// Blur: Gaussian
// ToDo: Switch to array Kernel instead of Texture kernel.
float4 PSGaussianBlur(VertDataOut vtx) : TARGET {
float2 uvOffset = float2(0, 0);
float4 final = u_image.SampleLevel(pointSampler, vtx.uv, 0)
* kernel.SampleLevel(pointSampler, (float2(0, u_radius - 1) * kernelTexel), 0).r;
for (int k = 1; k <= u_radius; k++) {
uvOffset += u_texelDelta;
float l_g = kernel.SampleLevel(pointSampler, (float2(k, u_radius - 1) * kernelTexel), 0).r;
float4 l_p = u_image.SampleLevel(pointSampler, vtx.uv + uvOffset, 0);
float4 l_n = u_image.SampleLevel(pointSampler, vtx.uv - uvOffset, 0);
final += (l_p + l_n) * l_g;
}
return final;
}
technique Gaussian
{
pass
{
vertex_shader = VSDefault(vtx);
pixel_shader = PSGaussianBlur(vtx);
}
}
/// Blur: Bilateral
float Bilateral(float x, float sigma) {
return 0.39894 * exp(-0.5 * (x*x) / (sigma*sigma)) / sigma;
}
float Bilateral3(float3 v, float sigma) {
// First part is Bilateral function (1.0 / (o * sqrt(2.0 * pivalue))) with o = 1
return 0.39894 * exp(-0.5 * dot(v,v) / (sigma*sigma)) / sigma;
}
float4 PSBilateralBlur(VertDataOut vtx) : TARGET {
float4 origin = u_image.SampleLevel(pointSampler, vtx.uv, 0);
float2 uvOffset = float2(0, 0);
float Z = 0.0;
float bZ = 1.0 / Bilateral(0.0, bilateralSharpness);
float3 color = float3(0, 0, 0);
for (int k = 1; k <= u_radius; k++) {
uvOffset += u_texelDelta;
// Bilateral Kernel
float bKernel = Bilateral(abs(k), bilateralSmoothing);
bKernel *= bKernel;
float bZKernel = bZ * bKernel;
// Sample Color
float3 l_p = u_image.SampleLevel(pointSampler, vtx.uv + uvOffset, 0).rgb;
float3 l_n = u_image.SampleLevel(pointSampler, vtx.uv - uvOffset, 0).rgb;
// Bilateral Stuff
float l_factor_p = Bilateral3(l_p - origin.rgb, bilateralSharpness) * bZKernel;
float l_factor_n = Bilateral3(l_n - origin.rgb, bilateralSharpness) * bZKernel;
Z = Z + l_factor_p + l_factor_n;
// Store Color
color += l_p * l_factor_p;
color += l_n * l_factor_n;
}
return float4(color.rgb / Z, origin.a);
}
technique Bilateral
{
pass
{
vertex_shader = VSDefault(vtx);
pixel_shader = PSBilateralBlur(vtx);
}
}

View file

@ -1,61 +0,0 @@
// Parameters
/// OBS
uniform float4x4 ViewProj;
/// Blur
uniform texture2d u_image;
uniform float2 u_imageSize;
uniform float2 u_imageTexel;
uniform int u_radius;
uniform int u_diameter;
uniform float2 u_texelDelta;
// Data
sampler_state pointSampler {
Filter = Point;
AddressU = Clamp;
AddressV = Clamp;
MinLOD = 0;
MaxLOD = 0;
};
struct VertDataIn {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
struct VertDataOut {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
VertDataOut VSDefault(VertDataIn v_in)
{
VertDataOut vert_out;
vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj);
vert_out.uv = v_in.uv;
return vert_out;
}
// Box Blur
float4 BlurFunc(float2 uv, float4 rgba) {
float4 final = rgba;
for (int k = 1; k <= u_radius; k++) {
final += u_image.SampleLevel(pointSampler, uv + (u_texelDelta * k), 0);
final += u_image.SampleLevel(pointSampler, uv - (u_texelDelta * k), 0);
}
return final / u_diameter;
}
float4 PSBox(VertDataOut v_in) : TARGET {
float4 rgba = u_image.SampleLevel(pointSampler, v_in.uv, 0);
return BlurFunc(v_in.uv, rgba);
}
technique Draw
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSBox(v_in);
}
}

View file

@ -1,68 +0,0 @@
// OBS Default
uniform float4x4 ViewProj;
// Settings (Shared)
uniform texture2d u_image;
uniform float2 u_imageSize;
uniform float2 u_imageTexel;
uniform int u_radius;
uniform int u_diameter;
uniform float2 u_texelDelta;
// Settings (Private)
//uniform float registerkernel[25];
uniform texture2d kernel;
uniform float2 kernelTexel;
sampler_state textureSampler {
Filter = Point;
AddressU = Clamp;
AddressV = Clamp;
MinLOD = 0;
MaxLOD = 0;
};
struct VertDataIn {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
struct VertDataOut {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
VertDataOut VSDefault(VertDataIn v_in)
{
VertDataOut vert_out;
vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj);
vert_out.uv = v_in.uv;
return vert_out;
}
float4 BlurFunc(float2 uv, float4 rgba) {
float2 uvOffset = float2(0, 0);
float4 final = rgba * kernel.SampleLevel(textureSampler, (float2(0, u_radius - 1) * kernelTexel), 0).r;
for (int k = 1; k <= u_radius; k++) {
uvOffset += u_texelDelta;
float l_g = kernel.SampleLevel(textureSampler, (float2(k, u_radius - 1) * kernelTexel), 0).r;
float4 l_p = u_image.SampleLevel(textureSampler, uv + uvOffset, 0);
float4 l_n = u_image.SampleLevel(textureSampler, uv - uvOffset, 0);
final += (l_p + l_n) * l_g;
}
return final;
}
float4 PSGaussian(VertDataOut v_in) : TARGET {
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
return BlurFunc(v_in.uv, rgba);
}
technique Draw
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSGaussian(v_in);
}
}

View file

@ -1,49 +0,0 @@
uniform matrix4 ViewProj;
uniform texture2d image;
uniform float2 imageTexel;
uniform int layer;
sampler_state textureSampler {
Filter = Point;
AddressU = Clamp;
AddressV = Clamp;
};
struct VertDataIn {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
struct VertDataOut {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
VertDataOut VSDefault(VertDataIn v_in)
{
VertDataOut vert_out;
vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj);
vert_out.uv = v_in.uv;
return vert_out;
}
float4 PSAverage(VertDataOut v_in) : TARGET
{
float4 rgba = 0;
for (float x = -1; x <= 1; x++) {
for (float y = -1; y <= 1; y++) {
rgba += image.Sample(textureSampler, v_in.uv + vec2(x,y) * imageTexel + imageTexel);
}
}
return rgba / 9.0;
}
technique Draw
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSAverage(v_in);
}
}

View file

@ -28,8 +28,9 @@ CustomShader.Texture.Type.Source="Source"
# Filter - Blur # Filter - Blur
Filter.Blur="Blur" Filter.Blur="Blur"
Filter.Blur.Type="Type" Filter.Blur.Type="Type"
Filter.Blur.Type.Description="The type of blur to apply:\n- 'Box' smoothes pixels equally.\n- 'Gaussian' applies a gaussian curve to the smoothed pixels.\n- 'Bilateral' is an edge detection variant of 'Gaussian'." Filter.Blur.Type.Description="The type of blur to apply:\n- 'Box' smoothes pixels equally.\n- 'Box Linear' uses linear sampling to reduce the GPU usage, sacrificing minimal quality.\n- 'Gaussian' applies a gaussian curve to the smoothed pixels.\n- 'Bilateral' is an edge detection variant of 'Gaussian'."
Filter.Blur.Type.Box="Box" Filter.Blur.Type.Box="Box"
Filter.Blur.Type.BoxLinear="Box Linear"
Filter.Blur.Type.Gaussian="Gaussian" Filter.Blur.Type.Gaussian="Gaussian"
Filter.Blur.Type.Bilateral="Bilateral" Filter.Blur.Type.Bilateral="Bilateral"
Filter.Blur.Size="Size (Pixel)" Filter.Blur.Size="Size (Pixel)"

View file

@ -39,6 +39,7 @@ extern "C" {
#define P_TYPE "Filter.Blur.Type" #define P_TYPE "Filter.Blur.Type"
#define P_TYPE_BOX "Filter.Blur.Type.Box" #define P_TYPE_BOX "Filter.Blur.Type.Box"
#define P_TYPE_BOXLINEAR "Filter.Blur.Type.BoxLinear"
#define P_TYPE_GAUSSIAN "Filter.Blur.Type.Gaussian" #define P_TYPE_GAUSSIAN "Filter.Blur.Type.Gaussian"
#define P_TYPE_BILATERAL "Filter.Blur.Type.Bilateral" #define P_TYPE_BILATERAL "Filter.Blur.Type.Bilateral"
#define P_SIZE "Filter.Blur.Size" #define P_SIZE "Filter.Blur.Size"
@ -137,8 +138,8 @@ bool filter::blur::blur_instance::apply_gaussian_param()
return true; return true;
} }
bool filter::blur::blur_instance::apply_mask_parameters(std::shared_ptr<gs::effect> effect, gs_texture_t* original_texture, bool filter::blur::blur_instance::apply_mask_parameters(std::shared_ptr<gs::effect> effect,
gs_texture_t* blurred_texture) gs_texture_t* original_texture, gs_texture_t* blurred_texture)
{ {
if (effect->has_parameter("image_orig")) { if (effect->has_parameter("image_orig")) {
effect->get_parameter("image_orig").set_texture(original_texture); effect->get_parameter("image_orig").set_texture(original_texture);
@ -203,7 +204,7 @@ bool filter::blur::blur_instance::apply_mask_parameters(std::shared_ptr<gs::effe
} }
bool filter::blur::blur_instance::modified_properties(void* ptr, obs_properties_t* props, obs_property* prop, bool filter::blur::blur_instance::modified_properties(void* ptr, obs_properties_t* props, obs_property* prop,
obs_data_t* settings) obs_data_t* settings)
{ {
bool showBilateral = (obs_data_get_int(settings, P_TYPE) == type::Bilateral); bool showBilateral = (obs_data_get_int(settings, P_TYPE) == type::Bilateral);
@ -297,6 +298,7 @@ obs_properties_t* filter::blur::blur_instance::get_properties()
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_TYPE))); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_TYPE)));
obs_property_set_modified_callback2(p, modified_properties, this); obs_property_set_modified_callback2(p, modified_properties, this);
obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_BOX), filter::blur::type::Box); obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_BOX), filter::blur::type::Box);
obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_BOXLINEAR), filter::blur::type::BoxLinear);
obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_GAUSSIAN), filter::blur::type::Gaussian); obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_GAUSSIAN), filter::blur::type::Gaussian);
obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_BILATERAL), filter::blur::type::Bilateral); obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_BILATERAL), filter::blur::type::Bilateral);
@ -356,7 +358,7 @@ obs_properties_t* filter::blur::blur_instance::get_properties()
p); p);
blur_factory::get()->enum_scenes([this, p](obs_scene_t* scene) { blur_factory::get()->enum_scenes([this, p](obs_scene_t* scene) {
struct data { struct data {
blur_instance* self; blur_instance* self;
obs_property_t* prop; obs_property_t* prop;
std::string parent_name; std::string parent_name;
}; };
@ -394,9 +396,10 @@ obs_properties_t* filter::blur::blur_instance::get_properties()
void filter::blur::blur_instance::update(obs_data_t* settings) void filter::blur::blur_instance::update(obs_data_t* settings)
{ {
type = (blur::type)obs_data_get_int(settings, P_TYPE); type = (blur::type)obs_data_get_int(settings, P_TYPE);
blur_effect = blur_factory::get()->get_effect(type); blur_effect = blur_factory::get()->get_effect(type);
size = (uint64_t)obs_data_get_int(settings, P_SIZE); blur_technique = blur_factory::get()->get_technique(type);
size = (uint64_t)obs_data_get_int(settings, P_SIZE);
// bilateral blur // bilateral blur
bilateral_smoothing = obs_data_get_double(settings, P_BILATERAL_SMOOTHING) / 100.0; bilateral_smoothing = obs_data_get_double(settings, P_BILATERAL_SMOOTHING) / 100.0;
@ -620,8 +623,6 @@ void filter::blur::blur_instance::video_render(gs_effect_t* effect)
std::make_tuple("Vertical", vertical_rendertarget, 0.0f, 1.0f / baseH), std::make_tuple("Vertical", vertical_rendertarget, 0.0f, 1.0f / baseH),
}; };
std::string pass = "Draw";
for (auto v : kvs) { for (auto v : kvs) {
const char* name = std::get<0>(v); const char* name = std::get<0>(v);
gs_texrender_t* rt = std::get<1>(v); gs_texrender_t* rt = std::get<1>(v);
@ -649,7 +650,7 @@ void filter::blur::blur_instance::video_render(gs_effect_t* effect)
gs_clear(GS_CLEAR_COLOR | GS_CLEAR_DEPTH, &black, 0, 0); gs_clear(GS_CLEAR_COLOR | GS_CLEAR_DEPTH, &black, 0, 0);
// Render // Render
while (gs_effect_loop(blur_effect->get_object(), pass.c_str())) { while (gs_effect_loop(this->blur_effect->get_object(), this->blur_technique.c_str())) {
gs_draw_sprite(intermediate, 0, baseW, baseH); gs_draw_sprite(intermediate, 0, baseW, baseH);
} }
@ -812,27 +813,9 @@ void filter::blur::blur_factory::on_list_fill()
obs_enter_graphics(); obs_enter_graphics();
{ {
char* file = obs_module_file("effects/box-blur.effect"); char* file = obs_module_file("effects/blur.effect");
try { try {
effects.insert_or_assign(type::Box, std::make_shared<gs::effect>(file)); blur_effect = std::make_shared<gs::effect>(file);
} catch (std::runtime_error ex) {
P_LOG_ERROR("<filter-blur> Loading effect '%s' failed with error(s): %s", file, ex.what());
}
bfree(file);
}
{
char* file = obs_module_file("effects/gaussian-blur.effect");
try {
effects.insert_or_assign(type::Gaussian, std::make_shared<gs::effect>(file));
} catch (std::runtime_error ex) {
P_LOG_ERROR("<filter-blur> Loading effect '%s' failed with error(s): %s", file, ex.what());
}
bfree(file);
}
{
char* file = obs_module_file("effects/bilateral-blur.effect");
try {
effects.insert_or_assign(type::Bilateral, std::make_shared<gs::effect>(file));
} catch (std::runtime_error ex) { } catch (std::runtime_error ex) {
P_LOG_ERROR("<filter-blur> Loading effect '%s' failed with error(s): %s", file, ex.what()); P_LOG_ERROR("<filter-blur> Loading effect '%s' failed with error(s): %s", file, ex.what());
} }
@ -864,7 +847,7 @@ void filter::blur::blur_factory::on_list_fill()
void filter::blur::blur_factory::on_list_empty() void filter::blur::blur_factory::on_list_empty()
{ {
obs_enter_graphics(); obs_enter_graphics();
effects.clear(); blur_effect.reset();
kernels.clear(); kernels.clear();
color_converter_effect.reset(); color_converter_effect.reset();
mask_effect.reset(); mask_effect.reset();
@ -1013,7 +996,7 @@ void filter::blur::blur_factory::video_render(void* inptr, gs_effect_t* effect)
void filter::blur::blur_factory::scene_create_handler(void* ptr, calldata_t* data) void filter::blur::blur_factory::scene_create_handler(void* ptr, calldata_t* data)
{ {
filter::blur::blur_factory* self = reinterpret_cast<filter::blur::blur_factory*>(ptr); filter::blur::blur_factory* self = reinterpret_cast<filter::blur::blur_factory*>(ptr);
obs_source_t* source = nullptr; obs_source_t* source = nullptr;
calldata_get_ptr(data, "source", &source); calldata_get_ptr(data, "source", &source);
obs_scene_t* scene = obs_scene_from_source(source); obs_scene_t* scene = obs_scene_from_source(source);
if (scene) { if (scene) {
@ -1024,7 +1007,7 @@ void filter::blur::blur_factory::scene_create_handler(void* ptr, calldata_t* dat
void filter::blur::blur_factory::scene_destroy_handler(void* ptr, calldata_t* data) void filter::blur::blur_factory::scene_destroy_handler(void* ptr, calldata_t* data)
{ {
filter::blur::blur_factory* self = reinterpret_cast<filter::blur::blur_factory*>(ptr); filter::blur::blur_factory* self = reinterpret_cast<filter::blur::blur_factory*>(ptr);
obs_source_t* source = nullptr; obs_source_t* source = nullptr;
calldata_get_ptr(data, "source", &source); calldata_get_ptr(data, "source", &source);
obs_scene_t* scene = obs_scene_from_source(source); obs_scene_t* scene = obs_scene_from_source(source);
if (scene) { if (scene) {
@ -1034,7 +1017,22 @@ void filter::blur::blur_factory::scene_destroy_handler(void* ptr, calldata_t* da
std::shared_ptr<gs::effect> filter::blur::blur_factory::get_effect(filter::blur::type type) std::shared_ptr<gs::effect> filter::blur::blur_factory::get_effect(filter::blur::type type)
{ {
return effects.at(type); return blur_effect;
}
std::string filter::blur::blur_factory::get_technique(filter::blur::type type)
{
switch (type) {
case type::Box:
return "Box";
case type::BoxLinear:
return "BoxLinear";
case type::Gaussian:
return "Gaussian";
case type::Bilateral:
return "Bilateral";
}
return "";
} }
std::shared_ptr<gs::effect> filter::blur::blur_factory::get_color_converter_effect() std::shared_ptr<gs::effect> filter::blur::blur_factory::get_color_converter_effect()

View file

@ -42,6 +42,7 @@ namespace filter {
namespace blur { namespace blur {
enum type : int64_t { enum type : int64_t {
Box, Box,
BoxLinear,
Gaussian, Gaussian,
Bilateral, Bilateral,
}; };
@ -61,6 +62,7 @@ namespace filter {
// blur // blur
std::shared_ptr<gs::effect> blur_effect; std::shared_ptr<gs::effect> blur_effect;
std::string blur_technique;
filter::blur::type type; filter::blur::type type;
uint64_t size; uint64_t size;
@ -134,11 +136,11 @@ namespace filter {
class blur_factory { class blur_factory {
obs_source_info source_info; obs_source_info source_info;
std::list<blur_instance*> sources; std::list<blur_instance*> sources;
std::shared_ptr<gs::effect> color_converter_effect; std::shared_ptr<gs::effect> color_converter_effect;
std::shared_ptr<gs::effect> mask_effect; std::shared_ptr<gs::effect> mask_effect;
std::map<filter::blur::type, std::shared_ptr<gs::effect>> effects; std::shared_ptr<gs::effect> blur_effect;
std::map<filter::blur::type, std::shared_ptr<gs::texture>> kernels; std::map<filter::blur::type, std::shared_ptr<gs::texture>> kernels;
std::map<std::string, obs_scene_t*> scenes; std::map<std::string, obs_scene_t*> scenes;
@ -177,6 +179,8 @@ namespace filter {
public: public:
std::shared_ptr<gs::effect> get_effect(filter::blur::type type); std::shared_ptr<gs::effect> get_effect(filter::blur::type type);
std::string get_technique(filter::blur::type type);
std::shared_ptr<gs::effect> get_color_converter_effect(); std::shared_ptr<gs::effect> get_color_converter_effect();
std::shared_ptr<gs::effect> get_mask_effect(); std::shared_ptr<gs::effect> get_mask_effect();
@ -188,8 +192,8 @@ namespace filter {
void enum_scenes(std::function<bool(obs_scene_t*)> fnc); void enum_scenes(std::function<bool(obs_scene_t*)> fnc);
public: // Singleton public: // Singleton
static void initialize(); static void initialize();
static void finalize(); static void finalize();
static blur_factory* get(); static blur_factory* get();
}; };