slang-shaders/scalenx/shaders/epx.slang
2021-02-12 21:37:55 -06:00

89 lines
2.2 KiB
Plaintext

#version 450
// EPX (Eric's Pixel Scaler)
// based on the description from Wikipedia:
// https://en.wikipedia.org/wiki/Pixel-art_scaling_algorithms#EPX/Scale2%C3%97/AdvMAME2%C3%97
// adapted for slang by hunterk
// license GPL, I think
layout(push_constant) uniform Push
{
vec4 SourceSize;
vec4 OriginalSize;
vec4 OutputSize;
uint FrameCount;
} params;
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;
void main()
{
gl_Position = global.MVP * Position;
vTexCoord = TexCoord * 1.00001;
}
#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source;
bool same(vec3 B, vec3 A0){
return all(equal(B, A0));
}
bool notsame(vec3 B, vec3 A0){
return any(notEqual(B, A0));
}
// sample with coordinate offsets
#define TEX(c,d) texture(Source, vTexCoord.xy + vec2(c,d) * params.SourceSize.zw).rgb
void main()
{
// The algorithm looks at the current pixel and the 4 surrounding cardinal pixels
// ___|_A_|___
// _C_|_P_|_B_
// | D |
// Our current pixel, P
vec3 P = TEX( 0., 0.);
// Input pixels
vec3 A = TEX( 0., 1.);
vec3 B = TEX( 1., 0.);
vec3 D = TEX( 0.,-1.);
vec3 C = TEX(-1., 0.);
// Output: 2x2 grid. Default to the current pixel color (Nearest magnification)
// ___one_|_two___
// three | four
vec3 one = P;
vec3 two = P;
vec3 three = P;
vec3 four = P;
// EPX algorithm rules:
// IF C==A AND C!=D AND A!=B => 1=A
// IF A==B AND A!=C AND B!=D => 2=B
// IF D==C AND D!=B AND C!=A => 3=C
// IF B==D AND B!=A AND D!=C => 4=D
one = (same(C, D) && notsame(C, A) && notsame(C, B)) ? C : P;
two = (same(D, B) && notsame(D, C) && notsame(D, A)) ? D : P;
three = (same(A, C) && notsame(A, B) && notsame(A, D)) ? A : P;
four = (same(B, A) && notsame(B, D) && notsame(B, C)) ? B : P;
vec2 px = fract(vTexCoord * params.SourceSize.xy);
// split the texels into 4 and assign one of our output pixels to each
FragColor.rgb = (px.x < 0.5) ? (px.y < 0.5 ? one : three) : (px.y < 0.5 ? two : four);
FragColor.a = 1.0;
}