mirror of
https://github.com/italicsjenga/slang-shaders.git
synced 2024-11-23 08:11:29 +11:00
164 lines
6.3 KiB
Plaintext
164 lines
6.3 KiB
Plaintext
|
/*
|
||
|
Scaling library v1.0 by fishku
|
||
|
Copyright (C) 2023
|
||
|
Public domain license (CC0)
|
||
|
|
||
|
This file acts like a library and should be included in another shader to be
|
||
|
used. For example usages, see the border/blur_fill shaders.
|
||
|
|
||
|
It's recommended to use these functions in the vertex shader pass, and pass
|
||
|
the data to the fragment pass.
|
||
|
|
||
|
Features:
|
||
|
- Cropping on each side
|
||
|
- Centering of image after crop has been applied
|
||
|
- Forcing of a certain aspect ratio
|
||
|
- Forcing of either vert. or horiz. integer scaling, or both
|
||
|
- Rotation support (0, 90, 180, 270 degrees).
|
||
|
|
||
|
Refactored from the version that used to be in the blur_fill shader.
|
||
|
|
||
|
Changelog:
|
||
|
v1.0: Initial conversion from blur_fill release. Add rotation support.
|
||
|
*/
|
||
|
|
||
|
vec4 get_rotated_crop(vec4 crop, uint rotation) {
|
||
|
switch (rotation) {
|
||
|
case 0:
|
||
|
default:
|
||
|
return crop;
|
||
|
case 1:
|
||
|
return crop.yzwx;
|
||
|
case 2:
|
||
|
return crop.zwxy;
|
||
|
case 3:
|
||
|
return crop.wxyz;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
vec2 get_rotated_size(vec2 x, uint rotation) {
|
||
|
switch (rotation) {
|
||
|
case 0:
|
||
|
case 2:
|
||
|
default:
|
||
|
return x;
|
||
|
case 1:
|
||
|
case 3:
|
||
|
return x.yx;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Get 2 corners of input in texel space, spanning the input image.
|
||
|
// corners.x and .y define the top-left corner, corners.z and .w define the
|
||
|
// bottom-right corner.
|
||
|
vec4 get_input_corners(vec2 input_size, vec4 crop, uint rotation) {
|
||
|
crop = get_rotated_crop(crop, rotation);
|
||
|
return vec4(crop.y, crop.x, input_size.x - crop.w, input_size.y - crop.z);
|
||
|
}
|
||
|
|
||
|
// Get adjusted center in input pixel coordinate system.
|
||
|
vec2 get_input_center(vec2 input_size, vec4 crop, uint rotation,
|
||
|
float center_after_cropping) {
|
||
|
crop = get_rotated_crop(crop, rotation);
|
||
|
return center_after_cropping > 0.5
|
||
|
? 0.5 * vec2(crop.y + input_size.x - crop.w,
|
||
|
crop.x + input_size.y - crop.z)
|
||
|
: vec2(0.49999) * input_size;
|
||
|
}
|
||
|
|
||
|
// Scaling from unit output to pixel input space.
|
||
|
vec2 get_scale_o2i(vec2 input_size, vec2 output_size, vec4 crop, uint rotation,
|
||
|
float center_after_cropping, float force_aspect_ratio,
|
||
|
vec2 aspect, vec2 force_integer_scaling,
|
||
|
bool output_size_is_final_viewport_size) {
|
||
|
crop = get_rotated_crop(crop, rotation);
|
||
|
if (output_size_is_final_viewport_size) {
|
||
|
output_size = get_rotated_size(output_size, rotation);
|
||
|
}
|
||
|
aspect = get_rotated_size(aspect, rotation);
|
||
|
// Aspect ratio before cropping.
|
||
|
// lambda_1 * input_pixels.x, lambda_2 * input_pixels.y,
|
||
|
// possibly corrected for forced aspect ratio
|
||
|
aspect = (force_aspect_ratio < 0.5
|
||
|
? output_size * input_size.yx
|
||
|
: (aspect.x < 0.5 || aspect.y < 0.5
|
||
|
? vec2(1.0)
|
||
|
: vec2(aspect.x, aspect.y) * input_size.yx));
|
||
|
// Pixels in input coord. space, after cropping.
|
||
|
input_size = input_size -
|
||
|
(center_after_cropping > 0.5
|
||
|
? vec2(crop.y + crop.w, crop.x + crop.z)
|
||
|
: 2.0 * vec2(min(crop.y, crop.w), min(crop.x, crop.z)));
|
||
|
|
||
|
force_integer_scaling = get_rotated_size(force_integer_scaling, rotation);
|
||
|
float scale_x, scale_y;
|
||
|
if (output_size.x / (input_size.x * aspect.x) <
|
||
|
output_size.y / (input_size.y * aspect.y)) {
|
||
|
// Scale will be limited by width. Calc x scale, then derive y scale
|
||
|
// using aspect ratio.
|
||
|
scale_x = output_size.x / input_size.x;
|
||
|
if (force_integer_scaling.x > 0.5 && scale_x > 1.0) {
|
||
|
scale_x = floor(scale_x);
|
||
|
}
|
||
|
scale_y = scale_x * aspect.y / aspect.x;
|
||
|
if (force_integer_scaling.y > 0.5 && scale_y > 1.0) {
|
||
|
scale_y = floor(scale_y);
|
||
|
}
|
||
|
} else {
|
||
|
// Scale will be limited by height.
|
||
|
scale_y = output_size.y / input_size.y;
|
||
|
if (force_integer_scaling.y > 0.5 && scale_y > 1.0) {
|
||
|
scale_y = floor(scale_y);
|
||
|
}
|
||
|
scale_x = scale_y * aspect.x / aspect.y;
|
||
|
if (force_integer_scaling.x > 0.5 && scale_x > 1.0) {
|
||
|
scale_x = floor(scale_x);
|
||
|
}
|
||
|
}
|
||
|
return output_size.xy / vec2(scale_x, scale_y);
|
||
|
}
|
||
|
|
||
|
// From unit output to pixel input space.
|
||
|
// coord_in_input_space = o2i(coord_in_output_space)
|
||
|
// This is used to sample from the input texture in the output pass.
|
||
|
// Version where scale is passed in.
|
||
|
vec2 o2i(vec2 x, vec2 input_size, vec4 crop, uint rotation,
|
||
|
float center_after_cropping, vec2 scale_o2i) {
|
||
|
return (x - 0.49999) * scale_o2i +
|
||
|
get_input_center(input_size, crop, rotation, center_after_cropping);
|
||
|
}
|
||
|
|
||
|
// Version that computes scale.
|
||
|
vec2 o2i(vec2 x, vec2 input_size, vec2 output_size, vec4 crop, uint rotation,
|
||
|
float center_after_cropping, float force_aspect_ratio, vec2 aspect,
|
||
|
vec2 force_integer_scaling, bool output_size_is_final_viewport_size) {
|
||
|
return o2i(x, input_size, crop, rotation, center_after_cropping,
|
||
|
get_scale_o2i(input_size, output_size, crop, rotation,
|
||
|
center_after_cropping, force_aspect_ratio, aspect,
|
||
|
force_integer_scaling,
|
||
|
output_size_is_final_viewport_size));
|
||
|
}
|
||
|
|
||
|
// From pixel input to unit output space.
|
||
|
// Version where scale is passed in.
|
||
|
vec2 i2o(vec2 x, vec2 input_size, vec4 crop, uint rotation,
|
||
|
float center_after_cropping, vec2 scale_o2i) {
|
||
|
return (x - get_input_center(input_size, crop, rotation,
|
||
|
center_after_cropping)) /
|
||
|
scale_o2i +
|
||
|
0.49999;
|
||
|
}
|
||
|
|
||
|
// Version that computes scale.
|
||
|
vec2 i2o(vec2 x, vec2 input_size, vec2 output_size, vec4 crop, uint rotation,
|
||
|
float center_after_cropping, float force_aspect_ratio, vec2 aspect,
|
||
|
vec2 force_integer_scaling, bool output_size_is_final_viewport_size) {
|
||
|
return (x - get_input_center(input_size, crop, rotation,
|
||
|
center_after_cropping)) /
|
||
|
get_scale_o2i(input_size, output_size, crop, rotation,
|
||
|
center_after_cropping, force_aspect_ratio, aspect,
|
||
|
force_integer_scaling,
|
||
|
output_size_is_final_viewport_size) +
|
||
|
0.49999;
|
||
|
}
|