obs-studio/libobs/data/area.effect

153 lines
3.6 KiB
Plaintext

uniform float4x4 ViewProj;
uniform float2 base_dimension;
uniform float2 base_dimension_i;
uniform texture2d image;
sampler_state textureSampler {
Filter = Linear;
AddressU = Clamp;
AddressV = Clamp;
};
struct VertData {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
struct VertInOut {
float2 uv : TEXCOORD0;
float4 pos : POSITION;
};
struct FragData {
float2 uv : TEXCOORD0;
};
VertInOut VSDefault(VertData vert_in)
{
VertInOut vert_out;
vert_out.pos = mul(float4(vert_in.pos.xyz, 1.0), ViewProj);
vert_out.uv = vert_in.uv;
return vert_out;
}
float4 DrawArea(float2 uv)
{
float2 uv_delta = float2(ddx(uv.x), ddy(uv.y));
// Handle potential OpenGL flip.
if (obs_glsl_compile)
uv_delta.y = abs(uv_delta.y);
float2 uv_min = uv - 0.5 * uv_delta;
float2 uv_max = uv_min + uv_delta;
float2 load_index_begin = floor(uv_min * base_dimension);
float2 load_index_end = ceil(uv_max * base_dimension);
float2 target_dimension = 1.0 / uv_delta;
float2 target_pos = uv * target_dimension;
float2 target_pos_min = target_pos - 0.5;
float2 target_pos_max = target_pos + 0.5;
float2 scale = base_dimension_i * target_dimension;
float4 total_color = float4(0.0, 0.0, 0.0, 0.0);
float load_index_y = load_index_begin.y;
do {
float source_y_min = load_index_y * scale.y;
float source_y_max = source_y_min + scale.y;
float y_min = max(source_y_min, target_pos_min.y);
float y_max = min(source_y_max, target_pos_max.y);
float height = y_max - y_min;
float load_index_x = load_index_begin.x;
do {
float source_x_min = load_index_x * scale.x;
float source_x_max = source_x_min + scale.x;
float x_min = max(source_x_min, target_pos_min.x);
float x_max = min(source_x_max, target_pos_max.x);
float width = x_max - x_min;
float area = width * height;
float4 color = image.Load(int3(load_index_x, load_index_y, 0));
total_color += area * color;
++load_index_x;
} while (load_index_x < load_index_end.x);
++load_index_y;
} while (load_index_y < load_index_end.y);
return total_color;
}
float4 PSDrawAreaRGBA(FragData frag_in) : TARGET
{
return DrawArea(frag_in.uv);
}
float4 PSDrawAreaRGBADivide(FragData frag_in) : TARGET
{
float4 rgba = DrawArea(frag_in.uv);
float alpha = rgba.a;
float multiplier = (alpha > 0.0) ? (1.0 / alpha) : 0.0;
return float4(rgba.rgb * multiplier, alpha);
}
float4 PSDrawAreaRGBAUpscale(FragData frag_in) : TARGET
{
float2 uv = frag_in.uv;
float2 uv_delta = float2(ddx(uv.x), ddy(uv.y));
// Handle potential OpenGL flip.
if (obs_glsl_compile)
uv_delta.y = abs(uv_delta.y);
float2 uv_min = uv - 0.5 * uv_delta;
float2 uv_max = uv_min + uv_delta;
float2 load_index_first = floor(uv_min * base_dimension);
float2 load_index_last = ceil(uv_max * base_dimension) - 1.0;
if (load_index_first.x < load_index_last.x) {
float uv_boundary_x = load_index_last.x * base_dimension_i.x;
uv.x = ((uv.x - uv_boundary_x) / uv_delta.x) * base_dimension_i.x + uv_boundary_x;
} else
uv.x = (load_index_first.x + 0.5) * base_dimension_i.x;
if (load_index_first.y < load_index_last.y) {
float uv_boundary_y = load_index_last.y * base_dimension_i.y;
uv.y = ((uv.y - uv_boundary_y) / uv_delta.y) * base_dimension_i.y + uv_boundary_y;
} else
uv.y = (load_index_first.y + 0.5) * base_dimension_i.y;
return image.Sample(textureSampler, uv);
}
technique Draw
{
pass
{
vertex_shader = VSDefault(vert_in);
pixel_shader = PSDrawAreaRGBA(frag_in);
}
}
technique DrawAlphaDivide
{
pass
{
vertex_shader = VSDefault(vert_in);
pixel_shader = PSDrawAreaRGBADivide(frag_in);
}
}
technique DrawUpscale
{
pass
{
vertex_shader = VSDefault(vert_in);
pixel_shader = PSDrawAreaRGBAUpscale(frag_in);
}
}