From 4f782f2415f8b9acc4df08fce4db98bc570c5a57 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Fri, 22 Jan 2016 05:34:02 -0800 Subject: [PATCH] obs-filters: Make mask/blend image center w/aspect by default Fixes what is arguably the most annoying feature of the mask/blend filter, the fact that the image always stretches to the entire source. It now centers and preserves aspect ratio by default, with an option to make it stretch and discard aspect ratio to make it operate as it did before. --- .../obs-filters/data/blend_add_filter.effect | 23 ++++++--- .../obs-filters/data/blend_mul_filter.effect | 23 ++++++--- .../obs-filters/data/blend_sub_filter.effect | 23 ++++++--- plugins/obs-filters/data/locale/en-US.ini | 1 + .../obs-filters/data/mask_alpha_filter.effect | 23 ++++++--- .../obs-filters/data/mask_color_filter.effect | 23 ++++++--- plugins/obs-filters/mask-filter.c | 48 ++++++++++++++++++- 7 files changed, 128 insertions(+), 36 deletions(-) diff --git a/plugins/obs-filters/data/blend_add_filter.effect b/plugins/obs-filters/data/blend_add_filter.effect index dc64c3408..ccb5107d5 100644 --- a/plugins/obs-filters/data/blend_add_filter.effect +++ b/plugins/obs-filters/data/blend_add_filter.effect @@ -6,6 +6,8 @@ uniform float3 color_range_max = {1.0, 1.0, 1.0}; uniform texture2d target; uniform float4 color; +uniform float2 mul_val; +uniform float2 add_val; sampler_state textureSampler { Filter = Linear; @@ -13,29 +15,36 @@ sampler_state textureSampler { AddressV = Clamp; }; -struct VertData { +struct VertDataIn { float4 pos : POSITION; float2 uv : TEXCOORD0; }; -VertData VSDefault(VertData v_in) +struct VertDataOut { + float4 pos : POSITION; + float2 uv : TEXCOORD0; + float2 uv2 : TEXCOORD1; +}; + +VertDataOut VSDefault(VertDataIn v_in) { - VertData vert_out; + VertDataOut vert_out; vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); vert_out.uv = v_in.uv; + vert_out.uv2 = v_in.uv * mul_val + add_val; return vert_out; } -float4 PSAddImageRGBA(VertData v_in) : TARGET +float4 PSAddImageRGBA(VertDataOut v_in) : TARGET { float4 rgba = image.Sample(textureSampler, v_in.uv) * color; - float4 targetRGB = target.Sample(textureSampler, v_in.uv); + float4 targetRGB = target.Sample(textureSampler, v_in.uv2); rgba.rgb = saturate(rgba.rgb + targetRGB.rgb); return rgba; } -float4 PSAddImageMatrix(VertData v_in) : TARGET +float4 PSAddImageMatrix(VertDataOut v_in) : TARGET { float4 yuv = image.Sample(textureSampler, v_in.uv); yuv.xyz = clamp(yuv.xyz, color_range_min, color_range_max); @@ -43,7 +52,7 @@ float4 PSAddImageMatrix(VertData v_in) : TARGET float4 rgba = saturate(mul(float4(yuv.xyz, 1.0), color_matrix)) * color; - float4 targetRGB = target.Sample(textureSampler, v_in.uv); + float4 targetRGB = target.Sample(textureSampler, v_in.uv2); rgba.rgb = saturate(rgba.rgb + targetRGB.rgb); return rgba; } diff --git a/plugins/obs-filters/data/blend_mul_filter.effect b/plugins/obs-filters/data/blend_mul_filter.effect index 6ec1a8152..94bbe5935 100644 --- a/plugins/obs-filters/data/blend_mul_filter.effect +++ b/plugins/obs-filters/data/blend_mul_filter.effect @@ -6,6 +6,8 @@ uniform float3 color_range_max = {1.0, 1.0, 1.0}; uniform texture2d target; uniform float4 color; +uniform float2 mul_val; +uniform float2 add_val; sampler_state textureSampler { Filter = Linear; @@ -13,29 +15,36 @@ sampler_state textureSampler { AddressV = Clamp; }; -struct VertData { +struct VertDataIn { float4 pos : POSITION; float2 uv : TEXCOORD0; }; -VertData VSDefault(VertData v_in) +struct VertDataOut { + float4 pos : POSITION; + float2 uv : TEXCOORD0; + float2 uv2 : TEXCOORD1; +}; + +VertDataOut VSDefault(VertDataIn v_in) { - VertData vert_out; + VertDataOut vert_out; vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); vert_out.uv = v_in.uv; + vert_out.uv2 = v_in.uv * mul_val + add_val; return vert_out; } -float4 PSMuliplyImageRGBA(VertData v_in) : TARGET +float4 PSMuliplyImageRGBA(VertDataOut v_in) : TARGET { float4 rgba = image.Sample(textureSampler, v_in.uv) * color; - float4 targetRGB = target.Sample(textureSampler, v_in.uv); + float4 targetRGB = target.Sample(textureSampler, v_in.uv2); rgba.rgb = saturate(rgba.rgb * targetRGB.rgb); return rgba; } -float4 PSMuliplyImageMatrix(VertData v_in) : TARGET +float4 PSMuliplyImageMatrix(VertDataOut v_in) : TARGET { float4 yuv = image.Sample(textureSampler, v_in.uv); yuv.xyz = clamp(yuv.xyz, color_range_min, color_range_max); @@ -43,7 +52,7 @@ float4 PSMuliplyImageMatrix(VertData v_in) : TARGET float4 rgba = saturate(mul(float4(yuv.xyz, 1.0), color_matrix)) * color; - float4 targetRGB = target.Sample(textureSampler, v_in.uv); + float4 targetRGB = target.Sample(textureSampler, v_in.uv2); rgba.rgb = saturate(rgba.rgb * targetRGB.rgb); return rgba; } diff --git a/plugins/obs-filters/data/blend_sub_filter.effect b/plugins/obs-filters/data/blend_sub_filter.effect index 841473419..5b63329d9 100644 --- a/plugins/obs-filters/data/blend_sub_filter.effect +++ b/plugins/obs-filters/data/blend_sub_filter.effect @@ -6,6 +6,8 @@ uniform float3 color_range_max = {1.0, 1.0, 1.0}; uniform texture2d target; uniform float4 color; +uniform float2 mul_val; +uniform float2 add_val; sampler_state textureSampler { Filter = Linear; @@ -13,29 +15,36 @@ sampler_state textureSampler { AddressV = Clamp; }; -struct VertData { +struct VertDataIn { float4 pos : POSITION; float2 uv : TEXCOORD0; }; -VertData VSDefault(VertData v_in) +struct VertDataOut { + float4 pos : POSITION; + float2 uv : TEXCOORD0; + float2 uv2 : TEXCOORD1; +}; + +VertDataOut VSDefault(VertDataIn v_in) { - VertData vert_out; + VertDataOut vert_out; vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); vert_out.uv = v_in.uv; + vert_out.uv2 = v_in.uv * mul_val + add_val; return vert_out; } -float4 PSSubtractImageRGBA(VertData v_in) : TARGET +float4 PSSubtractImageRGBA(VertDataOut v_in) : TARGET { float4 rgba = image.Sample(textureSampler, v_in.uv) * color; - float4 targetRGB = target.Sample(textureSampler, v_in.uv); + float4 targetRGB = target.Sample(textureSampler, v_in.uv2); rgba.rgb = saturate(rgba.rgb - targetRGB.rgb); return rgba; } -float4 PSSubtractImageMatrix(VertData v_in) : TARGET +float4 PSSubtractImageMatrix(VertDataOut v_in) : TARGET { float4 yuv = image.Sample(textureSampler, v_in.uv); yuv.xyz = clamp(yuv.xyz, color_range_min, color_range_max); @@ -43,7 +52,7 @@ float4 PSSubtractImageMatrix(VertData v_in) : TARGET float4 rgba = saturate(mul(float4(yuv.xyz, 1.0), color_matrix)) * color; - float4 targetRGB = target.Sample(textureSampler, v_in.uv); + float4 targetRGB = target.Sample(textureSampler, v_in.uv2); rgba.rgb = saturate(rgba.rgb - targetRGB.rgb); return rgba; } diff --git a/plugins/obs-filters/data/locale/en-US.ini b/plugins/obs-filters/data/locale/en-US.ini index 927188c30..a3d9ccacb 100644 --- a/plugins/obs-filters/data/locale/en-US.ini +++ b/plugins/obs-filters/data/locale/en-US.ini @@ -50,3 +50,4 @@ NoiseGate.AttackTime="Attack Time (milliseconds)" NoiseGate.HoldTime="Hold Time (milliseconds)" NoiseGate.ReleaseTime="Release Time (milliseconds)" Gain.GainDB="Gain (dB)" +StretchImage="Stretch Image (discard image aspect ratio)" diff --git a/plugins/obs-filters/data/mask_alpha_filter.effect b/plugins/obs-filters/data/mask_alpha_filter.effect index e02f94150..72f3d7a9a 100644 --- a/plugins/obs-filters/data/mask_alpha_filter.effect +++ b/plugins/obs-filters/data/mask_alpha_filter.effect @@ -6,6 +6,8 @@ uniform float3 color_range_max = {1.0, 1.0, 1.0}; uniform texture2d target; uniform float4 color; +uniform float2 mul_val; +uniform float2 add_val; sampler_state textureSampler { Filter = Linear; @@ -13,29 +15,36 @@ sampler_state textureSampler { AddressV = Clamp; }; -struct VertData { +struct VertDataIn { float4 pos : POSITION; float2 uv : TEXCOORD0; }; -VertData VSDefault(VertData v_in) +struct VertDataOut { + float4 pos : POSITION; + float2 uv : TEXCOORD0; + float2 uv2 : TEXCOORD1; +}; + +VertDataOut VSDefault(VertDataIn v_in) { - VertData vert_out; + VertDataOut vert_out; vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); vert_out.uv = v_in.uv; + vert_out.uv2 = v_in.uv * mul_val + add_val; return vert_out; } -float4 PSAlphaMaskRGBA(VertData v_in) : TARGET +float4 PSAlphaMaskRGBA(VertDataOut v_in) : TARGET { float4 rgba = image.Sample(textureSampler, v_in.uv) * color; - float4 targetRGB = target.Sample(textureSampler, v_in.uv); + float4 targetRGB = target.Sample(textureSampler, v_in.uv2); rgba.a *= targetRGB.a; return rgba; } -float4 PSAlphaMaskMatrix(VertData v_in) : TARGET +float4 PSAlphaMaskMatrix(VertDataOut v_in) : TARGET { float4 yuv = image.Sample(textureSampler, v_in.uv); yuv.xyz = clamp(yuv.xyz, color_range_min, color_range_max); @@ -43,7 +52,7 @@ float4 PSAlphaMaskMatrix(VertData v_in) : TARGET float4 rgba = saturate(mul(float4(yuv.xyz, 1.0), color_matrix)) * color; - float4 targetRGB = target.Sample(textureSampler, v_in.uv); + float4 targetRGB = target.Sample(textureSampler, v_in.uv2); rgba.a = targetRGB.a; return rgba; } diff --git a/plugins/obs-filters/data/mask_color_filter.effect b/plugins/obs-filters/data/mask_color_filter.effect index 0e0fd3ba6..6e0ab7e72 100644 --- a/plugins/obs-filters/data/mask_color_filter.effect +++ b/plugins/obs-filters/data/mask_color_filter.effect @@ -6,6 +6,8 @@ uniform float3 color_range_max = {1.0, 1.0, 1.0}; uniform texture2d target; uniform float4 color; +uniform float2 mul_val; +uniform float2 add_val; sampler_state textureSampler { Filter = Linear; @@ -13,29 +15,36 @@ sampler_state textureSampler { AddressV = Clamp; }; -struct VertData { +struct VertDataIn { float4 pos : POSITION; float2 uv : TEXCOORD0; }; -VertData VSDefault(VertData v_in) +struct VertDataOut { + float4 pos : POSITION; + float2 uv : TEXCOORD0; + float2 uv2 : TEXCOORD1; +}; + +VertDataOut VSDefault(VertDataIn v_in) { - VertData vert_out; + VertDataOut vert_out; vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); vert_out.uv = v_in.uv; + vert_out.uv2 = v_in.uv * mul_val + add_val; return vert_out; } -float4 PSColorMaskRGBA(VertData v_in) : TARGET +float4 PSColorMaskRGBA(VertDataOut v_in) : TARGET { float4 rgba = image.Sample(textureSampler, v_in.uv) * color; - float4 targetRGB = target.Sample(textureSampler, v_in.uv); + float4 targetRGB = target.Sample(textureSampler, v_in.uv2); rgba.a *= (targetRGB.r + targetRGB.g + targetRGB.b) / 3.0; return rgba; } -float4 PSColorMaskMatrix(VertData v_in) : TARGET +float4 PSColorMaskMatrix(VertDataOut v_in) : TARGET { float4 yuv = image.Sample(textureSampler, v_in.uv); yuv.xyz = clamp(yuv.xyz, color_range_min, color_range_max); @@ -43,7 +52,7 @@ float4 PSColorMaskMatrix(VertData v_in) : TARGET float4 rgba = saturate(mul(float4(yuv.xyz, 1.0), color_matrix)) * color; - float4 targetRGB = target.Sample(textureSampler, v_in.uv); + float4 targetRGB = target.Sample(textureSampler, v_in.uv2); rgba.a = (targetRGB.r + targetRGB.g + targetRGB.b) / 3.0; return rgba; } diff --git a/plugins/obs-filters/mask-filter.c b/plugins/obs-filters/mask-filter.c index 4d00d2db5..dfe930e02 100644 --- a/plugins/obs-filters/mask-filter.c +++ b/plugins/obs-filters/mask-filter.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -6,11 +7,13 @@ #define SETTING_IMAGE_PATH "image_path" #define SETTING_COLOR "color" #define SETTING_OPACITY "opacity" +#define SETTING_STRETCH "stretch" #define TEXT_TYPE obs_module_text("Type") #define TEXT_IMAGE_PATH obs_module_text("Path") #define TEXT_COLOR obs_module_text("Color") #define TEXT_OPACITY obs_module_text("Opacity") +#define TEXT_STRETCH obs_module_text("StretchImage") #define TEXT_PATH_IMAGES obs_module_text("BrowsePath.Images") #define TEXT_PATH_ALL_FILES obs_module_text("BrowsePath.AllFiles") @@ -20,6 +23,7 @@ struct mask_filter_data { gs_texture_t *target; struct vec4 color; + bool lock_aspect; }; static const char *mask_filter_get_name(void *unused) @@ -46,6 +50,7 @@ static void mask_filter_update(void *data, obs_data_t *settings) gs_texture_destroy(filter->target); filter->target = (path) ? gs_texture_create_from_file(path) : NULL; + filter->lock_aspect = !obs_data_get_bool(settings, SETTING_STRETCH); effect_path = obs_module_file(effect_file); gs_effect_destroy(filter->effect); @@ -100,6 +105,7 @@ static obs_properties_t *mask_filter_properties(void *data) OBS_PATH_FILE, filter_str.array, NULL); obs_properties_add_color(props, SETTING_COLOR, TEXT_COLOR); obs_properties_add_int(props, SETTING_OPACITY, TEXT_OPACITY, 0, 100, 1); + obs_properties_add_bool(props, SETTING_STRETCH, TEXT_STRETCH); dstr_free(&filter_str); @@ -132,13 +138,47 @@ static void mask_filter_destroy(void *data) static void mask_filter_render(void *data, gs_effect_t *effect) { struct mask_filter_data *filter = data; + obs_source_t *target = obs_filter_get_target(filter->context); gs_eparam_t *param; + struct vec2 add_val = {0}; + struct vec2 mul_val = {1.0f, 1.0f}; - if (!filter->target || !filter->effect) { + if (!target || !filter->target || !filter->effect) { obs_source_skip_video_filter(filter->context); return; } + if (filter->lock_aspect) { + struct vec2 source_size; + struct vec2 mask_size; + struct vec2 mask_temp; + float source_aspect; + float mask_aspect; + bool size_to_x; + float fix; + + source_size.x = (float)obs_source_get_base_width(target); + source_size.y = (float)obs_source_get_base_height(target); + mask_size.x = (float)gs_texture_get_width(filter->target); + mask_size.y = (float)gs_texture_get_height(filter->target); + + source_aspect = source_size.x / source_size.y; + mask_aspect = mask_size.x / mask_size.y; + size_to_x = (source_aspect < mask_aspect); + + fix = size_to_x ? + (source_size.x / mask_size.x) : + (source_size.y / mask_size.y); + + vec2_mulf(&mask_size, &mask_size, fix); + vec2_div(&mul_val, &source_size, &mask_size); + vec2_mulf(&source_size, &source_size, 0.5f); + vec2_mulf(&mask_temp, &mask_size, 0.5f); + vec2_sub(&add_val, &source_size, &mask_temp); + vec2_neg(&add_val, &add_val); + vec2_div(&add_val, &add_val, &mask_size); + } + obs_source_process_filter_begin(filter->context, GS_RGBA, OBS_ALLOW_DIRECT_RENDERING); @@ -148,6 +188,12 @@ static void mask_filter_render(void *data, gs_effect_t *effect) param = gs_effect_get_param_by_name(filter->effect, "color"); gs_effect_set_vec4(param, &filter->color); + param = gs_effect_get_param_by_name(filter->effect, "mul_val"); + gs_effect_set_vec2(param, &mul_val); + + param = gs_effect_get_param_by_name(filter->effect, "add_val"); + gs_effect_set_vec2(param, &add_val); + obs_source_process_filter_end(filter->context, filter->effect, 0, 0); UNUSED_PARAMETER(effect);