mirror of
https://github.com/italicsjenga/slang-shaders.git
synced 2024-11-25 08:51:32 +11:00
c1488579ee
* Scaling: Add overscale option * Bump versions
247 lines
9.3 KiB
Plaintext
247 lines
9.3 KiB
Plaintext
#version 450
|
|
|
|
// See compose.slang for copyright and other information.
|
|
|
|
#include "../../../misc/shaders/crop_and_scale/crop_and_scale.slang"
|
|
#include "parameters.slang"
|
|
|
|
layout(push_constant) uniform Push {
|
|
vec4 InputSize;
|
|
vec4 FinalViewportSize;
|
|
uint Rotation;
|
|
// Own settings
|
|
float EXTEND_H;
|
|
float EXTEND_V;
|
|
float MIRROR_BLUR;
|
|
float SAMPLE_SIZE;
|
|
// From crop and scale, scaling section
|
|
float FORCE_ASPECT_RATIO;
|
|
float ASPECT_H;
|
|
float ASPECT_V;
|
|
float FORCE_INTEGER_SCALING_H;
|
|
float FORCE_INTEGER_SCALING_V;
|
|
float OVERSCALE;
|
|
// From crop and scale, cropping section
|
|
float OS_CROP_TOP;
|
|
float OS_CROP_BOTTOM;
|
|
float OS_CROP_LEFT;
|
|
float OS_CROP_RIGHT;
|
|
float CENTER_AFTER_CROPPING;
|
|
}
|
|
param;
|
|
|
|
layout(std140, set = 0, binding = 0) uniform UBO { mat4 MVP; }
|
|
global;
|
|
|
|
#pragma stage vertex
|
|
layout(location = 0) in vec4 Position;
|
|
layout(location = 1) in vec2 TexCoord;
|
|
layout(location = 0) out vec2 vTexCoord;
|
|
layout(location = 1) out vec2 tx_coord;
|
|
layout(location = 2) out vec4 input_corners;
|
|
|
|
void main() {
|
|
gl_Position = global.MVP * Position;
|
|
vTexCoord = TexCoord;
|
|
const vec4 crop = vec4(param.OS_CROP_TOP, param.OS_CROP_LEFT,
|
|
param.OS_CROP_BOTTOM, param.OS_CROP_RIGHT);
|
|
const vec2 scale_o2i = get_scale_o2i(
|
|
param.InputSize.xy, param.FinalViewportSize.xy, crop, param.Rotation,
|
|
param.CENTER_AFTER_CROPPING, param.FORCE_ASPECT_RATIO,
|
|
vec2(param.ASPECT_H, param.ASPECT_V),
|
|
vec2(param.FORCE_INTEGER_SCALING_H, param.FORCE_INTEGER_SCALING_V), param.OVERSCALE,
|
|
/* output_size_is_final_viewport_size = */ true);
|
|
tx_coord = o2i(vTexCoord, param.InputSize.xy, crop, param.Rotation,
|
|
param.CENTER_AFTER_CROPPING, scale_o2i);
|
|
input_corners = get_input_corners(param.InputSize.xy, crop, param.Rotation);
|
|
}
|
|
|
|
#pragma stage fragment
|
|
layout(location = 0) in vec2 vTexCoord;
|
|
layout(location = 1) in vec2 tx_coord;
|
|
layout(location = 2) in vec4 input_corners;
|
|
layout(location = 0) out vec4 FragColor;
|
|
layout(set = 0, binding = 2) uniform sampler2D Source;
|
|
|
|
float min_of_vec4(vec4 i) { return min(min(i.x, i.y), min(i.z, i.w)); }
|
|
|
|
int argmin(vec4 i) {
|
|
const vec4 m = vec4(min_of_vec4(i));
|
|
const vec4 ma = step(i, m) * vec4(0.0, -1.0, -2.0, -3.0);
|
|
return -int(min_of_vec4(ma));
|
|
}
|
|
|
|
// Returns a coordinate in [0, w) when repeating that interval (and optionally
|
|
// mirroring).
|
|
float mirrored_repeat(float w, float x) {
|
|
const float phase = mod(x, w);
|
|
if (param.MIRROR_BLUR < 0.5) {
|
|
return phase;
|
|
}
|
|
const int period = int(x / w);
|
|
return period % 2 == 1 != x > 0.0 ? phase : w - phase;
|
|
}
|
|
|
|
float extend_left(vec2 coord, vec4 input_corners) {
|
|
return input_corners.x +
|
|
mirrored_repeat(param.SAMPLE_SIZE, coord.x - input_corners.x);
|
|
}
|
|
|
|
float extend_right(vec2 coord, vec4 input_corners) {
|
|
return input_corners.z -
|
|
mirrored_repeat(param.SAMPLE_SIZE, input_corners.z - coord.x);
|
|
}
|
|
|
|
float extend_top(vec2 coord, vec4 input_corners) {
|
|
return input_corners.y +
|
|
mirrored_repeat(param.SAMPLE_SIZE, coord.y - input_corners.y);
|
|
}
|
|
|
|
float extend_bottom(vec2 coord, vec4 input_corners) {
|
|
return input_corners.w -
|
|
mirrored_repeat(param.SAMPLE_SIZE, input_corners.w - coord.y);
|
|
}
|
|
|
|
// This function samples in a very specific way which is the foundation for
|
|
// blurring later.
|
|
// - If the sample coordinate is outside of the cropped input, Either black is
|
|
// returned if blur extension is turned off, or a repeated pattern from the
|
|
// sampling frame band is returned.
|
|
// - If the coordinate is inside the cropped input and within the frame band
|
|
// given by SAMPLE_SIZE, the original texture sample is returned.
|
|
// - If the coordinate is further inside than the frame band, a mirrored
|
|
// repeating sample is returned. The side of the frame that is sampled is given
|
|
// by the one that is closest to the sampled point.
|
|
vec3 sample_mirrored_frame(sampler2D tex, vec2 tx_coord, vec4 input_corners) {
|
|
const vec2 extend_fill =
|
|
get_rotated_size(vec2(param.EXTEND_H, param.EXTEND_V), param.Rotation);
|
|
if (tx_coord.x < input_corners.x) {
|
|
if (extend_fill.x < 0.5) {
|
|
return vec3(0.0);
|
|
}
|
|
if (tx_coord.y < input_corners.y) {
|
|
// Top left corner extension
|
|
if (extend_fill.y < 0.5) {
|
|
return vec3(0.0);
|
|
}
|
|
return texture(tex, vec2(extend_left(tx_coord, input_corners),
|
|
extend_top(tx_coord, input_corners)) *
|
|
param.InputSize.zw)
|
|
.rgb;
|
|
} else if (tx_coord.y < input_corners.w) {
|
|
// Left extension
|
|
return texture(tex, vec2(extend_left(tx_coord, input_corners),
|
|
tx_coord.y) *
|
|
param.InputSize.zw)
|
|
.rgb;
|
|
} else {
|
|
// Bottom left corner extension
|
|
if (extend_fill.y < 0.5) {
|
|
return vec3(0.0);
|
|
}
|
|
return texture(tex, vec2(extend_left(tx_coord, input_corners),
|
|
extend_bottom(tx_coord, input_corners)) *
|
|
param.InputSize.zw)
|
|
.rgb;
|
|
}
|
|
} else if (tx_coord.x < input_corners.z) {
|
|
if (tx_coord.y < input_corners.y) {
|
|
if (extend_fill.y < 0.5) {
|
|
return vec3(0.0);
|
|
}
|
|
// Top extension
|
|
return texture(tex, vec2(tx_coord.x,
|
|
extend_top(tx_coord, input_corners)) *
|
|
param.InputSize.zw)
|
|
.rgb;
|
|
} else if (tx_coord.y < input_corners.w) {
|
|
const vec4 inner_corners =
|
|
input_corners + vec4(param.SAMPLE_SIZE, param.SAMPLE_SIZE,
|
|
-param.SAMPLE_SIZE, -param.SAMPLE_SIZE);
|
|
if (any(lessThan(tx_coord, inner_corners.xy)) ||
|
|
any(greaterThanEqual(tx_coord, inner_corners.zw))) {
|
|
// In frame band
|
|
return texture(tex, tx_coord * param.InputSize.zw).rgb;
|
|
}
|
|
// Innermost -- mirrored repeat sampling from nearest side
|
|
const vec4 distances = vec4(
|
|
tx_coord.x - inner_corners.x, inner_corners.z - tx_coord.x,
|
|
tx_coord.y - inner_corners.y, inner_corners.w - tx_coord.y);
|
|
switch (argmin(distances)) {
|
|
case 0:
|
|
// left
|
|
return texture(tex,
|
|
vec2(extend_left(tx_coord, input_corners),
|
|
tx_coord.y) *
|
|
param.InputSize.zw)
|
|
.rgb;
|
|
case 1:
|
|
// right
|
|
return texture(tex,
|
|
vec2(extend_right(tx_coord, input_corners),
|
|
tx_coord.y) *
|
|
param.InputSize.zw)
|
|
.rgb;
|
|
case 2:
|
|
// top
|
|
return texture(tex,
|
|
vec2(tx_coord.x,
|
|
extend_top(tx_coord, input_corners)) *
|
|
param.InputSize.zw)
|
|
.rgb;
|
|
case 3:
|
|
default:
|
|
// bottom
|
|
return texture(tex, vec2(tx_coord.x,
|
|
extend_bottom(tx_coord,
|
|
input_corners)) *
|
|
param.InputSize.zw)
|
|
.rgb;
|
|
}
|
|
} else {
|
|
if (extend_fill.y < 0.5) {
|
|
return vec3(0.0);
|
|
}
|
|
// Bottom extension
|
|
return texture(tex, vec2(tx_coord.x,
|
|
extend_bottom(tx_coord, input_corners)) *
|
|
param.InputSize.zw)
|
|
.rgb;
|
|
}
|
|
} else {
|
|
if (extend_fill.x < 0.5) {
|
|
return vec3(0.0);
|
|
}
|
|
if (tx_coord.y < input_corners.y) {
|
|
// Top right corner extension
|
|
if (extend_fill.y < 0.5) {
|
|
return vec3(0.0);
|
|
}
|
|
return texture(tex, vec2(extend_right(tx_coord, input_corners),
|
|
extend_top(tx_coord, input_corners)) *
|
|
param.InputSize.zw)
|
|
.rgb;
|
|
} else if (tx_coord.y < input_corners.w) {
|
|
// Right extension
|
|
return texture(tex, vec2(extend_right(tx_coord, input_corners),
|
|
tx_coord.y) *
|
|
param.InputSize.zw)
|
|
.rgb;
|
|
} else {
|
|
// Bottom right corner extension
|
|
if (extend_fill.y < 0.5) {
|
|
return vec3(0.0);
|
|
}
|
|
return texture(tex, vec2(extend_right(tx_coord, input_corners),
|
|
extend_bottom(tx_coord, input_corners)) *
|
|
param.InputSize.zw)
|
|
.rgb;
|
|
}
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
FragColor =
|
|
vec4(sample_mirrored_frame(Source, tx_coord, input_corners), 1.0);
|
|
}
|