diff --git a/Effects/Effects.vcxproj b/Effects/Effects.vcxproj index faf08aa3c..403ef019e 100644 --- a/Effects/Effects.vcxproj +++ b/Effects/Effects.vcxproj @@ -315,6 +315,11 @@ Document + + + Document + + diff --git a/Effects/Effects.vcxproj.filters b/Effects/Effects.vcxproj.filters index 3165c5e89..805e04a88 100644 --- a/Effects/Effects.vcxproj.filters +++ b/Effects/Effects.vcxproj.filters @@ -67,5 +67,6 @@ + \ No newline at end of file diff --git a/Effects/MMPX.hlsl b/Effects/MMPX.hlsl new file mode 100644 index 000000000..0659c9b5a --- /dev/null +++ b/Effects/MMPX.hlsl @@ -0,0 +1,134 @@ +// MMPX +// 移植自 https://casual-effects.com/research/McGuire2021PixelArt/index.html + +//!MAGPIE EFFECT +//!VERSION 2 +//!OUTPUT_WIDTH INPUT_WIDTH * 2 +//!OUTPUT_HEIGHT INPUT_HEIGHT * 2 + + +//!TEXTURE +Texture2D INPUT; + +//!SAMPLER +//!FILTER POINT +SamplerState sam; + + +//!PASS 1 +//!IN INPUT +//!BLOCK_SIZE 16 +//!NUM_THREADS 64 + + +#define src(x, y) INPUT.SampleLevel(sam, float2(x, y) * GetInputPt(), 0).rgb + +float luma(float3 C) { + return C.r + C.g + C.b; +} + +bool all_eq2(float3 B, float3 A0, float3 A1) { + return all(B == A0) && all(B == A1); +} + +bool all_eq3(float3 B, float3 A0, float3 A1, float3 A2) { + return all(B == A0) && all(B == A1) && all(B == A2); +} + +bool all_eq4(float3 B, float3 A0, float3 A1, float3 A2, float3 A3) { + return all(B == A0) && all(B == A1) && all(B == A2) && all(B == A3); +} + +bool any_eq3(float3 B, float3 A0, float3 A1, float3 A2) { + return all(B == A0) || all(B == A1) || all(B == A2); +} + +bool none_eq2(float3 B, float3 A0, float3 A1) { + return any(B != A0) && any(B != A1); +} + +bool none_eq4(float3 B, float3 A0, float3 A1, float3 A2, float3 A3) { + return any(B != A0) && any(B != A1) && any(B != A2) && any(B != A3); +} + +void Pass1(uint2 blockStart, uint3 threadId) { + uint2 gxy = (Rmp8x8(threadId.x) << 1) + blockStart; + + if (!CheckViewport(gxy)) { + return; + } + + float srcX = (gxy.x >> 1) + 0.5f; + float srcY = (gxy.y >> 1) + 0.5f; + + float3 A = src(srcX - 1, srcY - 1), B = src(srcX, srcY - 1), C = src(srcX + 1, srcY - 1); + float3 D = src(srcX - 1, srcY + 0), E = src(srcX, srcY + 0), F = src(srcX + 1, srcY + 0); + float3 G = src(srcX - 1, srcY + 1), H = src(srcX, srcY + 1), I = src(srcX + 1, srcY + 1); + + float3 J = E, K = E, L = E, M = E; + + if (any(A != E) || any(B != E) || any(C != E) || any(D != E) || any(F != E) || any(G != E) || any(H != E) || any(I != E)) { + float3 P = src(srcX, srcY - 2), S = src(srcX, srcY + 2); + float3 Q = src(srcX - 2, srcY), R = src(srcX + 2, srcY); + float Bl = luma(B), Dl = luma(D), El = luma(E), Fl = luma(F), Hl = luma(H); + + // 1:1 slope rules + if ((all(D == B) && any(D != H) && any(D != F)) && (El >= Dl || all(E == A)) && any_eq3(E, A, C, G) && ((El < Dl) || any(A != D) || any(E != P) || any(E != Q))) J = D; + if ((all(B == F) && any(B != D) && any(B != H)) && (El >= Bl || all(E == C)) && any_eq3(E, A, C, I) && ((El < Bl) || any(C != B) || any(E != P) || any(E != R))) K = B; + if ((all(H == D) && any(H != F) && any(H != B)) && (El >= Hl || all(E == G)) && any_eq3(E, A, G, I) && ((El < Hl) || any(G != H) || any(E != S) || any(E != Q))) L = H; + if ((all(F == H) && any(F != B) && any(F != D)) && (El >= Fl || all(E == I)) && any_eq3(E, C, G, I) && ((El < Fl) || any(I != H) || any(E != R) || any(E != S))) M = F; + + // Intersection rules + if ((any(E != F) && all_eq4(E, C, I, D, Q) && all_eq2(F, B, H)) && (any(F != src(srcX + 3, srcY)))) K = M = F; + if ((any(E != D) && all_eq4(E, A, G, F, R) && all_eq2(D, B, H)) && (any(D != src(srcX - 3, srcY)))) J = L = D; + if ((any(E != H) && all_eq4(E, G, I, B, P) && all_eq2(H, D, F)) && (any(H != src(srcX, srcY + 3)))) L = M = H; + if ((any(E != B) && all_eq4(E, A, C, H, S) && all_eq2(B, D, F)) && (any(B != src(srcX, srcY - 3)))) J = K = B; + if (Bl < El && all_eq4(E, G, H, I, S) && none_eq4(E, A, D, C, F)) J = K = B; + if (Hl < El && all_eq4(E, A, B, C, P) && none_eq4(E, D, G, I, F)) L = M = H; + if (Fl < El && all_eq4(E, A, D, G, Q) && none_eq4(E, B, C, I, H)) K = M = F; + if (Dl < El && all_eq4(E, C, F, I, R) && none_eq4(E, B, A, G, H)) J = L = D; + + // 2:1 slope rules + if (any(H != B)) { + if (any(H != A) && any(H != E) && any(H != C)) { + if (all_eq3(H, G, F, R) && none_eq2(H, D, src(srcX + 2, srcY - 1))) L = M; + if (all_eq3(H, I, D, Q) && none_eq2(H, F, src(srcX - 2, srcY - 1))) M = L; + } + + if (any(B != I) && any(B != G) && any(B != E)) { + if (all_eq3(B, A, F, R) && none_eq2(B, D, src(srcX + 2, srcY + 1))) J = K; + if (all_eq3(B, C, D, Q) && none_eq2(B, F, src(srcX - 2, srcY + 1))) K = J; + } + } // H !== B + + if (any(F != D)) { + if (any(D != I) && any(D != E) && any(D != C)) { + if (all_eq3(D, A, H, S) && none_eq2(D, B, src(srcX + 1, srcY + 2))) J = L; + if (all_eq3(D, G, B, P) && none_eq2(D, H, src(srcX + 1, srcY - 2))) L = J; + } + + if (any(F != E) && any(F != A) && any(F != G)) { + if (all_eq3(F, C, H, S) && none_eq2(F, B, src(srcX - 1, srcY + 2))) K = M; + if (all_eq3(F, I, B, P) && none_eq2(F, H, src(srcX - 1, srcY - 2))) M = K; + } + } // F !== D + } // not constant + + // Write four pixels at once + WriteToOutput(gxy, J); + + ++gxy.x; + if (CheckViewport(gxy)) { + WriteToOutput(gxy, K); + } + + ++gxy.y; + if (CheckViewport(gxy)) { + WriteToOutput(gxy, M); + } + + --gxy.x; + if (CheckViewport(gxy)) { + WriteToOutput(gxy, L); + } +}