mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Merge pull request #20755 from crashGG/mmpx-enhace
enhance MMPX algorithm Final Addendum
This commit is contained in:
+254
-203
@@ -6,7 +6,7 @@
|
||||
2025 Enhanced by CrashGG.
|
||||
*/
|
||||
|
||||
// Performs 2x upscaling
|
||||
// Performs 2x upscaling.
|
||||
|
||||
#define ABGR8 uint
|
||||
|
||||
@@ -17,28 +17,38 @@
|
||||
Normalization loss: Using readColor (without 'u') reads as floats (vec4), mapping integer range (0-255) to [0.0, 1.0], causing precision loss (255→1.0, 1→0.0039215686...).
|
||||
The unpackUnorm4x8 function in MMPX converts uint to vec4 (normalized floats) - this step is lossy.
|
||||
*/
|
||||
|
||||
ABGR8 src(int x, int y) {
|
||||
return readColoru(uvec2(clamp(x, 0, params.width - 1), clamp(y, 0, params.height - 1)));
|
||||
}
|
||||
|
||||
|
||||
// This luma is only for brightness decision mechanism. Each alpha point multiplies the final output
|
||||
//
|
||||
/*
|
||||
// Original luminance decision mechanism where small alpha changes cause significant output amplification
|
||||
uint luma(ABGR8 C) {
|
||||
uint alpha = (C & 0xFF000000u) >> 24;
|
||||
return (((C & 0x00FF0000u) >> 16) + ((C & 0x0000FF00u) >> 8) + (C & 0x000000FFu) + 1u) * (256u - alpha);
|
||||
}
|
||||
//
|
||||
// Modified: Linear brightness decision mechanism
|
||||
/*
|
||||
uint luma(ABGR8 C) {
|
||||
uint alpha = (C >> 24) & 0xFFu; // Simplified bit operations
|
||||
if (alpha == 0u) return 1530u; // Ensure fully transparent pixels return max value 1530
|
||||
uint rgbSum = ((C >> 16) & 0xFFu) + ((C >> 8) & 0xFFu) + (C & 0xFFu);
|
||||
float factor = 1.0f + (255.0f - alpha) * 0.00392157f; // Multiplication equivalent to division by 255
|
||||
return uint(rgbSum * factor);
|
||||
}
|
||||
*/
|
||||
//
|
||||
// Modified ternary alpha segmentation for efficiency optimization (LUT possible)
|
||||
uint luma(ABGR8 C) {
|
||||
uint alpha = (C & 0xFF000000u) >> 24;
|
||||
|
||||
uint sum = ((C & 0x00FF0000u) >> 16) +
|
||||
((C & 0x0000FF00u) >> 8) +
|
||||
(C & 0x000000FFu) + 1u;
|
||||
|
||||
uint alphafactor =
|
||||
(alpha == 0) ? 7000 : // Fully transparent
|
||||
(alpha > 217) ? 1000 : // ≈0.8535534×255 (Two golden cuts)
|
||||
(alpha > 157) ? 2000 : // ≈0.618034×255 (One golden cut)
|
||||
(alpha > 97) ? 3000 : // ≈0.381966×255 (Short golden cut)
|
||||
(alpha > 37) ? 4000 : 5000; // ≈0.1464466×255 (Two short golden cuts)
|
||||
|
||||
return sum + alphafactor;
|
||||
}
|
||||
//
|
||||
|
||||
uvec4 extractPIX(ABGR8 color) {
|
||||
uint r = (color >> 0) & 0xFFu;
|
||||
uint g = (color >> 8) & 0xFFu;
|
||||
@@ -47,33 +57,27 @@ uvec4 extractPIX(ABGR8 color) {
|
||||
return uvec4(r, g, b, a);
|
||||
}
|
||||
|
||||
// RGB approximate equality (RGB Euclidean distance ≈0.00932276 after golden ratio^3), alpha difference within 14.59% (golden ratio^2)
|
||||
|
||||
// Approximate RGB equality (Euclidean distance threshold ≈0.00932276) and alpha difference <14.59% (≈37.2/255)
|
||||
bool same(ABGR8 B, ABGR8 A0) {
|
||||
uvec4 b_pix = extractPIX(B);
|
||||
uvec4 a0_pix = extractPIX(A0);
|
||||
|
||||
// Calculate sum of squared RGB differences
|
||||
// Sum of squared RGB differences
|
||||
ivec3 diff = ivec3(b_pix.rgb) - ivec3(a0_pix.rgb);
|
||||
|
||||
// Calculate alpha difference (0-255 range)
|
||||
uint alphaDiff = abs(int(b_pix.a) - int(a0_pix.a));
|
||||
|
||||
// 14.59%≈37.2
|
||||
bool alphaDiffCheck = alphaDiff < 38u;
|
||||
|
||||
bool alphaDiffCheck = alphaDiff < 38u; // 5.57% ≈14.21, 14.59%≈37.2
|
||||
return dot(diff, diff) < 606u && alphaDiffCheck;
|
||||
}
|
||||
|
||||
// Checks exact RGB equality (morphology), ignores alpha
|
||||
// Full RGBA equality
|
||||
bool fullsame(ABGR8 B, ABGR8 A0){
|
||||
|
||||
return B == A0; //exact RGB match
|
||||
return B == A0;
|
||||
}
|
||||
|
||||
// Full difference including alpha channel
|
||||
// RGBA inequality
|
||||
bool notsame(ABGR8 B, ABGR8 A0){
|
||||
return (B!=A0);
|
||||
return B != A0;
|
||||
}
|
||||
|
||||
bool all_eq2(ABGR8 B, ABGR8 A0, ABGR8 A1) {
|
||||
@@ -105,101 +109,79 @@ bool none_eq4(ABGR8 B, ABGR8 A0, ABGR8 A1, ABGR8 A2, ABGR8 A3) {
|
||||
}
|
||||
|
||||
/////////////////////// Test Colors ///////////////////////
|
||||
vec4 testcolor = vec4(1.0, 0.0, 1.0, 1.0); // Magenta (opaque)
|
||||
vec4 testcolor2 = vec4(0.0, 1.0, 1.0, 1.0); // Cyan (opaque)
|
||||
//vec4 testcolor = vec4(1.0, 0.0, 1.0, 1.0); // Magenta (opaque)
|
||||
//vec4 testcolor2 = vec4(0.0, 1.0, 1.0, 1.0); // Cyan (opaque)
|
||||
//vec4 testcolor3 = vec4(1.0, 1.0, 0.0, 1.0); // Yellow (opaque)
|
||||
//vec4 testcolor4 = vec4(1.0, 1.0, 1.0, 1.0); // White (opaque)
|
||||
|
||||
float LumaFactor(vec4 col1, vec4 col2) {
|
||||
// Calculate brightness difference using RGB average (0-1 range)
|
||||
// Calculate luminance difference (0-1) using RGB average
|
||||
float LumaDiff = abs((col1.r + col1.g + col1.b) - (col2.r + col2.g + col2.b))*0.3333333;
|
||||
// Apply golden ratio scaling (0.618 - 1.618)
|
||||
float alphaDiff = abs(col1.a - col2.a);
|
||||
// Golden ratio scaling (0.618 - 1.618)
|
||||
float LumaGolden = (1.618034 - LumaDiff) * (1.618034 - LumaDiff); // Squared for dot() operations
|
||||
return LumaGolden;
|
||||
|
||||
return LumaGolden/(1.0 - alphaDiff); // Amplify result with alpha difference
|
||||
}
|
||||
|
||||
|
||||
vec4 admixC(ABGR8 X1, ABGR8 X2, vec4 rgbaE) {
|
||||
// Unpack ABGR8 to RGBA float vector (0.0-1.0 range)
|
||||
// Type-C: Weak blending dominance. Returns original if conditions unmet to avoid artifacts.
|
||||
if (rgbaE.a < 0.01) return rgbaE; // Handle transparent center
|
||||
|
||||
vec4 rgbaX1 = unpackUnorm4x8(X1);
|
||||
vec4 rgbaX2 = unpackUnorm4x8(X2);
|
||||
|
||||
// Extract RGB components
|
||||
vec3 rgbX1 = rgbaX1.rgb;
|
||||
vec3 rgbX2 = rgbaX2.rgb;
|
||||
vec3 rgbE = rgbaE.rgb;
|
||||
|
||||
// Return early if both sides are dark (RGB magnitude <0.05)
|
||||
if (dot(rgbX1, rgbX1) < 0.05 && dot(rgbX2, rgbX2) < 0.05) return rgbaE;
|
||||
|
||||
// Return early if both sides are fully transparent
|
||||
// Return if both sides are black (avoid blending)
|
||||
if (dot(rgbaX1.rgb, rgbaX1.rgb) < 0.05 && dot(rgbaX2.rgb, rgbaX2.rgb) < 0.05) return rgbaE;
|
||||
// Return if both sides are transparent
|
||||
if (rgbaX1.a < 0.01 && rgbaX2.a < 0.01) return rgbaE;
|
||||
|
||||
// Calculate squared Euclidean distance to reference color
|
||||
float rgbDistX1 = dot(rgbX1 - rgbE, rgbX1 - rgbE);
|
||||
float rgbDistX2 = dot(rgbX2 - rgbE, rgbX2 - rgbE);
|
||||
// Calculate squared Euclidean distance
|
||||
float rgbaDistX1 = dot(rgbaX1 - rgbaE, rgbaX1 - rgbaE);
|
||||
float rgbaDistX2 = dot(rgbaX2 - rgbaE, rgbaX2 - rgbaE);
|
||||
|
||||
// Apply brightness factor adjustment
|
||||
float rgb_lumaX1 = rgbDistX1 * LumaFactor(rgbaX1, rgbaE);
|
||||
float rgb_lumaX2 = rgbDistX2 * LumaFactor(rgbaX2, rgbaE);
|
||||
// Apply luminance factor adjustment
|
||||
float rgb_lumaX1 = rgbaDistX1 * LumaFactor(rgbaX1, rgbaE);
|
||||
float rgb_lumaX2 = rgbaDistX2 * LumaFactor(rgbaX2, rgbaE);
|
||||
|
||||
// Select closer reference color
|
||||
bool useX1 = rgb_lumaX1 < rgb_lumaX2;
|
||||
float rgb_luma = useX1 ? rgb_lumaX1 : rgb_lumaX2;
|
||||
vec4 rgbaX = useX1 ? rgbaX1 : rgbaX2;
|
||||
|
||||
// Avoid copying X directly if center is transparent (could cause artifacts)
|
||||
if (rgbaE.a < 0.01) return rgbaE;
|
||||
|
||||
// Blend or retain original color
|
||||
// Blend or return original
|
||||
return (rgb_luma < 0.75) ? mix(rgbaX, rgbaE, 0.5) : rgbaE;
|
||||
}
|
||||
|
||||
vec4 admixK(ABGR8 X, vec4 rgbaE) {
|
||||
// Unpack ABGR8 to RGBA float vector (0.0-1.0 range)
|
||||
vec4 rgbaX = unpackUnorm4x8(X);
|
||||
// Type-K: Weak blending. Return original if transparent.
|
||||
if (rgbaX.a < 0.01 || rgbaE.a < 0.01) return rgbaE;
|
||||
|
||||
// Return E if X is transparent
|
||||
if (rgbaX.a < 0.01) return rgbaE;
|
||||
|
||||
// Return X if E is transparent
|
||||
if (rgbaE.a < 0.01) return rgbaX;
|
||||
// Weighted dot product difference with luminance
|
||||
float rgbaDist = dot(rgbaX - rgbaE, rgbaX - rgbaE);
|
||||
float rgb_luma = rgbaDist * LumaFactor(rgbaX, rgbaE);
|
||||
|
||||
// Extract RGB components
|
||||
vec3 rgbX = rgbaX.rgb;
|
||||
vec3 rgbE = rgbaE.rgb;
|
||||
|
||||
// Calculate weighted squared distance with brightness factor
|
||||
float rgbDist = dot(rgbX - rgbE, rgbX - rgbE);
|
||||
float rgb_luma = rgbDist * LumaFactor(rgbaX, rgbaE);
|
||||
|
||||
// Blend based on threshold
|
||||
return (rgb_luma < 0.75) ? mix(rgbaX, rgbaE, 0.381966) : rgbaE;
|
||||
}
|
||||
|
||||
vec4 admixL(vec4 rgbaX, vec4 rgbaE) {
|
||||
// If E is transparent, return X
|
||||
if (rgbaE.a < 0.01) return rgbaX;
|
||||
|
||||
// If X is transparent, return E
|
||||
if (rgbaX.a < 0.01) return rgbaE;
|
||||
|
||||
// Extract RGB components
|
||||
vec3 rgbX = rgbaX.rgb;
|
||||
vec3 rgbE = rgbaE.rgb;
|
||||
|
||||
// Calculate squared RGB distance
|
||||
float rgbDist = dot(rgbX - rgbE, rgbX - rgbE);
|
||||
|
||||
// Check for nearly identical pixels
|
||||
if (rgbDist < 0.00136041) return rgbaE;
|
||||
vec4 admixL(vec4 rgbaX, vec4 rgbaE, ABGR8 S) {
|
||||
// Type-L: Strong blending dominance
|
||||
if (rgbaE.a < 0.01) return rgbaX; // Copy target if E transparent
|
||||
if (rgbaX.a < 0.01) return rgbaE; // Return E if X transparent
|
||||
|
||||
// Apply brightness factor adjustment
|
||||
float rgb_luma = rgbDist * LumaFactor(rgbaX, rgbaE);
|
||||
|
||||
// Blend result
|
||||
float rgbaDist = dot(rgbaX - rgbaE, rgbaX - rgbaE);
|
||||
if (rgbaDist < 0.00136041) return rgbaX; // Return if nearly identical
|
||||
|
||||
vec4 rgbaS = unpackUnorm4x8(S);
|
||||
float rgbaXSDist = dot(rgbaX - rgbaS, rgbaX - rgbaS);
|
||||
if (rgbaXSDist > 0.00136041) return rgbaX; // Return if X differs from S (already blended)
|
||||
|
||||
float rgb_luma = rgbaDist * LumaFactor(rgbaX, rgbaE);
|
||||
return (rgb_luma < 0.75) ? mix(rgbaX, rgbaE, 0.381966) : rgbaX;
|
||||
}
|
||||
|
||||
/* Main corner logic with X-cross detection
|
||||
/* Main corner detection with X-cross check
|
||||
P
|
||||
┌───┬───┬───┐ ┌───┬───┬───┐
|
||||
│ A │ B │ C │ │ A │ B2│ 1 │
|
||||
@@ -208,23 +190,18 @@ vec4 admixL(vec4 rgbaX, vec4 rgbaE) {
|
||||
├───┼───┼───┤ ├───┼───┼───┤
|
||||
│ G │ H │ I │ │ 5 │ 4 │ 3 │
|
||||
└───┴───┴───┘ └───┴───┴───┘
|
||||
Euclidean Formula: √(ΔR² + ΔG² + ΔB²)
|
||||
Black↔White: 1.732, Black↔RGB: 1.0, White↔R↔G↔B: 1.414
|
||||
|
||||
Squared Distance: dot(Δ,Δ) avoids sqrt (10x cheaper)
|
||||
Black↔White: 3.0, Black↔RGB: 1.0, White↔R↔G↔B: 2.0
|
||||
|
||||
Golden Ratio Thresholds:
|
||||
Euclidean: 0.382 0.5 0.618 0.382²
|
||||
Squared: 0.4377 0.75 1.1459 0.06386
|
||||
|
||||
Euclidean: √(ΔR² + ΔG² + ΔB²)
|
||||
Black↔White: 1.732, Black↔RGB: 1.0, White↔R/G/B: 1.414
|
||||
Dot product: dot(LA-LB, LA-LB) = Euclidean² (faster)
|
||||
Black↔White: 3.0, Black↔RGB: 1.0, White↔R/G/B: 2.0
|
||||
|
||||
Golden ratio positions (Euclidean): 0.382, 0.5, 0.618, 0.382²
|
||||
Corresponding dot thresholds: 0.4377, 0.75, 1.1459, 0.06386
|
||||
*/
|
||||
vec4 admixX(ABGR8 LE, ABGR8 LB1, ABGR8 LB2, ABGR8 LA, ABGR8 L1, ABGR8 L2, ABGR8 L3, ABGR8 L4, ABGR8 L5, ABGR8 LP, ABGR8 LQ) {
|
||||
// First check using approximate pixels to prevent false positives on gradient lines
|
||||
vec4 rgbaLE = unpackUnorm4x8(LE);
|
||||
if (fullsame(LE,LB1)||fullsame(LE,LB2)) return rgbaLE;
|
||||
if (fullsame(LE,LB1)||fullsame(LE,LB2)) return rgbaLE; // Early exit if identical
|
||||
|
||||
// Unpack neighbor colors
|
||||
vec4 rgbaLB1 = unpackUnorm4x8(LB1);
|
||||
vec4 rgbaLB2 = unpackUnorm4x8(LB2);
|
||||
vec4 rgbaLA = unpackUnorm4x8(LA);
|
||||
@@ -236,95 +213,95 @@ vec4 admixX(ABGR8 LE, ABGR8 LB1, ABGR8 LB2, ABGR8 LA, ABGR8 L1, ABGR8 L2, ABGR8
|
||||
vec4 rgbaLP = unpackUnorm4x8(LP);
|
||||
vec4 rgbaLQ = unpackUnorm4x8(LQ);
|
||||
|
||||
// Define LB blend candidate. Handle transparency edge cases
|
||||
|
||||
// Define LB blending (handle transparency)
|
||||
vec4 rgbaLB = mix(rgbaLB1, rgbaLB2, 0.5);
|
||||
if (rgbaLB1.a < 0.01 ) rgbaLB=rgbaLB2;
|
||||
if (rgbaLB2.a < 0.01 ) rgbaLB=rgbaLB1;
|
||||
// If the RGB difference between the two LBs is large, the alpha of the side with less alpha can be used after mixing to reduce burrs
|
||||
if (rgbaLB1.a < rgbaLB.a ) rgbaLB.a=rgbaLB1.a; else rgbaLB.a=rgbaLB2.a;
|
||||
if (rgbaLB1.a < rgbaLB.a ) rgbaLB.a=rgbaLB1.a; else rgbaLB.a=rgbaLB2.a; // Reduce artifacts in gradients (e.g., "Jojo's Wall")
|
||||
|
||||
// Calculate squared RGB distance and brightness adjustment
|
||||
// Calculate RGBA dot product difference
|
||||
float rgbaDist = dot(rgbaLB - rgbaLE, rgbaLB - rgbaLE);
|
||||
float rgb_luma = rgbaDist * LumaFactor(rgbaLB, rgbaLE);
|
||||
float alphaDiff = abs((rgbaLB1.a + rgbaLB2.a) - rgbaLE.a * 2 );
|
||||
bool LBLEalpha0 = rgbaLB.a < 0.01 || rgbaLE.a < 0.01; // Transparency check
|
||||
|
||||
// X-cross pattern detection core logic
|
||||
bool LBLEalpha0 = rgbaLB.a < 0.01 || rgbaLE.a < 0.01; // Transparency flag
|
||||
|
||||
// Cross pattern detection (core rule)
|
||||
if (same(LE,LA)) {
|
||||
// Weak blend for very similar pixels to avoid artifacts
|
||||
if (rgbaDist < 0.06386) return mix(rgbaLE,rgbaLB,0.381966);
|
||||
if (rgbaDist < 0.06386) return mix(rgbaLE,rgbaLB,0.381966); // Weak blend for near-identical pixels
|
||||
|
||||
// Special pattern: Tuning fork
|
||||
bool same_LB1_L4 = same(LB1,L4);
|
||||
bool same_LB1_L5 = same(LB1,L5);
|
||||
bool same_LB2_L1 = same(LB2,L1);
|
||||
bool same_LB2_L2 = same(LB2,L2);
|
||||
if ( same_LB1_L4 && same_LB2_L1 && !same_LB2_L2 || same_LB1_L5 && same_LB2_L2 && !same_LB1_L4 ) return rgbaLE;
|
||||
if ( (same_LB1_L4 && same_LB2_L1 && !same_LB2_L2) ||
|
||||
(same_LB1_L5 && same_LB2_L2 && !same_LB1_L4) ) return rgbaLE;
|
||||
|
||||
// Special pattern: Large block cross
|
||||
bool same_LB2_LP = same(LB2,LP);
|
||||
bool same_LB1_LQ = same(LB1,LQ);
|
||||
bool same_LE_L2 = same(LE,L2);
|
||||
bool same_LE_L4 = same(LE,L4);
|
||||
// Special pattern: Large block cross
|
||||
if (same_LB2_L1 && same_LB1_L5 && (same(LB2,LP) && same_LE_L2 || same(LB1,LQ) && same_LE_L4)) return rgbaLE;
|
||||
|
||||
if (same_LB2_L1 && same_LB1_L5 && (same_LB2_LP && same_LE_L2 || same_LB1_LQ && same_LE_L4) ) return rgbaLE;
|
||||
|
||||
// Special pattern: Diagonal cross grid
|
||||
// Diagonal grid cross
|
||||
bool same_LE_L1 = same(LE,L1);
|
||||
bool same_LE_L3 = same(LE,L3);
|
||||
bool same_LE_L5 = same(LE,L5);
|
||||
|
||||
// A point
|
||||
if (same_LE_L1 && same_LE_L3 && same_LE_L5 && !same_LE_L2 && !same_LE_L4) return rgbaLE;
|
||||
bool same_LB1_L3 = same(LB1,L3);
|
||||
bool same_LB2_L3 = same(LB2,L3);
|
||||
if ( same_LE_L1 && same_LE_L3 && same_LE_L5 && !same_LE_L2 && !same_LE_L4 ) return rgbaLE;
|
||||
|
||||
// B point
|
||||
if ( same_LB2_L2 && same_LB1_L4 && !same_LB2_L1 && !same_LB1_L5 && !same_LB1_L3&& !same_LB2_L3 ) return rgbaLE;
|
||||
if ( same_LB2_L2 && same_LB1_L4 && !same_LB2_L1 && !same_LB1_L5 && !same(LB1,L3)&& !same(LB2,L3) ) return rgbaLE;
|
||||
|
||||
// Scoring system for cross patterns
|
||||
|
||||
// Scoring system for pattern recognition
|
||||
int score1 = 0; // Diagonal pattern score
|
||||
int score2 = 0; // Straight pattern score
|
||||
int scoreBonus = 0;
|
||||
|
||||
// Diagonal pattern scoring
|
||||
score1 += int(same_LE_L3);
|
||||
score1 += int(same_LE_L1);
|
||||
score1 += int(same_LE_L5);
|
||||
score1 += int(same(L2, L4));
|
||||
score1 += int(same(LA, LP));
|
||||
score1 += int(same(LA, LQ));
|
||||
score1 += int(same_LE_L3);
|
||||
|
||||
score1 += int(same_LE_L1);
|
||||
score1 += int(same_LE_L5);
|
||||
score1 += int(same(L2, L4));
|
||||
|
||||
score1 += int(same(LA, LP));
|
||||
score1 += int(same(LA, LQ));
|
||||
// Diagonal Y
|
||||
if ( score1<1) {
|
||||
if (same_LE_L2 && same_LB2_L1 || same_LE_L4 && same_LB1_L5 ) return rgbaLE;
|
||||
}
|
||||
score1 += int(same_LB2_L2);
|
||||
score1 += int(same_LB1_L4);
|
||||
|
||||
score1 += int(same_LB2_L2) + int(same_LB1_L4);
|
||||
|
||||
// Straight pattern scoring
|
||||
score2 += int(fullsame(LP, LB2) && fullsame(L5, LB1));
|
||||
score2 += int(fullsame(LQ, LB1) && fullsame(L1, LB2));
|
||||
|
||||
// Penalize large brightness differences
|
||||
float LumaDiff = abs((rgbaLE.r + rgbaLE.g + rgbaLE.b + rgbaLE.a) - (rgbaLB.r + rgbaLB.g + rgbaLB.b + rgbaLB.a))*0.3333333;
|
||||
if (LumaDiff > 0.8541 ) scoreBonus -= 1;
|
||||
if (alphaDiff > 1.0) scoreBonus -= 1; // Points are deducted when the cross-pixel alpha difference exceeds half
|
||||
// Penalize high luminance/alpha differences
|
||||
float LumaDiff = abs((rgbaLE.r+rgbaLE.g+rgbaLE.b+rgbaLE.a)-(rgbaLB.r+rgbaLB.g+rgbaLB.b+rgbaLB.a))*0.3333333;
|
||||
if (LumaDiff > 0.8541) scoreBonus -= 1; // High luminance difference penalty
|
||||
if (alphaDiff > 1.0) scoreBonus -= 1; // High alpha difference penalty
|
||||
|
||||
score1 += scoreBonus;
|
||||
score2 += scoreBonus;
|
||||
|
||||
// Blend based on scores and thresholds
|
||||
if (rgb_luma < 0.75 && (score1 >= 1 || score2 >= 1)) return (LBLEalpha0) ? rgbaLE : mix(rgbaLE, rgbaLB,0.5);
|
||||
if (rgb_luma < 1.1459 && (score1 == 1 && score2 >= 1)) return (LBLEalpha0) ? rgbaLE : mix(rgbaLE, rgbaLB,0.381966);
|
||||
if (score1 < 2 && score2 >= 1) return (LBLEalpha0) ? rgbaLE : mix(rgbaLE, rgbaLB,0.145898);
|
||||
if (rgb_luma < 0.75 && (score1 >= 1 || score2 >= 1))
|
||||
return LBLEalpha0 ? rgbaLE : mix(rgbaLE, rgbaLB, 0.5);
|
||||
if (rgb_luma < 1.1459 && (score1 == 1 && score2 >= 1))
|
||||
return LBLEalpha0 ? rgbaLE : mix(rgbaLE, rgbaLB, 0.381966);
|
||||
if (score1 < 2 && score2 >= 1)
|
||||
return LBLEalpha0 ? rgbaLE : mix(rgbaLE, rgbaLB, 0.145898);
|
||||
|
||||
// Final decision for strong patterns
|
||||
return (score1 >= 2) ? rgbaLB : rgbaLE;
|
||||
return (score1 >= 2) ? rgbaLB : rgbaLE; // Final decision
|
||||
}
|
||||
|
||||
// Non-cross patterns
|
||||
if (LBLEalpha0) return rgbaLB;
|
||||
if (fullsame(LB1,LB2)) return (rgb_luma < 0.75) ? mix(rgbaLB, rgbaLE,0.381966) : rgbaLB;
|
||||
return (rgb_luma < 0.75) ? mix(rgbaLB, rgbaLE,0.5) : rgbaLB;
|
||||
if (LBLEalpha0) return rgbaLB; // Handle transparency
|
||||
if (notsame(LB1,LB2)) return (rgb_luma < 0.75) ? mix(rgbaLB, rgbaLE, 0.5) : rgbaLB; // Gradient artifact prevention
|
||||
if (fullsame(LB1,LA)) return rgbaLB; // Avoid blending on edges
|
||||
return (rgb_luma < 0.75) ? mix(rgbaLB, rgbaLE, 0.381966) : rgbaLB; // Default weak blend
|
||||
}
|
||||
|
||||
|
||||
@@ -337,100 +314,174 @@ void applyScaling(uvec2 xy) {
|
||||
ABGR8 D = src(srcX - 1, srcY + 0), E = src(srcX, srcY + 0), F = src(srcX + 1, srcY + 0);
|
||||
ABGR8 G = src(srcX - 1, srcY + 1), H = src(srcX, srcY + 1), I = src(srcX + 1, srcY + 1);
|
||||
|
||||
// Default output pixels (center color)
|
||||
// Default output: center color (E)
|
||||
vec4 centerColor = unpackUnorm4x8(E);
|
||||
vec4 J = centerColor, K = centerColor, L = centerColor, M = centerColor;
|
||||
|
||||
// Only process if neighborhood isn't uniform
|
||||
// Process if neighborhood is non-uniform
|
||||
if (((A ^ E) | (B ^ E) | (C ^ E) | (D ^ E) | (F ^ E) | (G ^ E) | (H ^ E) | (I ^ E)) != 0u) {
|
||||
// Extended sampling for pattern detection
|
||||
ABGR8 P = src(srcX, srcY - 2), S = src(srcX, srcY + 2);
|
||||
ABGR8 Q = src(srcX - 2, srcY), R = src(srcX + 2, srcY);
|
||||
ABGR8 Bl = luma(B), Dl = luma(D), El = luma(E), Fl = luma(F), Hl = luma(H);
|
||||
|
||||
// Main scaling rules (J, K, L, M calculation)
|
||||
if ((same(D,B) && none_eq2(D,H,F) && none_eq2(B,H,F)) && ((El>=Dl&&El>=Bl) || fullsame(E,A)) && any_eq3(E,A,C,G) && ((El<Dl&&El<Bl) || none_eq2(A,D,B) || notsame(E,P) || notsame(E,Q)) ) J=admixX(E,D,B,A,C,F,I,H,G,P,Q);
|
||||
if ((same(B,F) && none_eq2(B,D,H) && none_eq2(F,D,H)) && ((El>=Bl&&El>=Fl) || fullsame(E,C)) && any_eq3(E,A,C,I) && ((El<Bl&&El<Fl) || none_eq2(C,B,F) || notsame(E,P) || notsame(E,R)) ) K=admixX(E,F,B,C,A,D,G,H,I,P,R);
|
||||
if ((same(H,D) && none_eq2(H,F,B) && none_eq2(D,F,B)) && ((El>=Hl&&El>=Dl) || fullsame(E,G)) && any_eq3(E,A,G,I) && ((El<Hl&&El<Dl) || none_eq2(G,H,D) || notsame(E,S) || notsame(E,Q)) ) L=admixX(E,D,H,G,I,F,C,B,A,S,Q);
|
||||
if ((same(F,H) && none_eq2(F,B,D) && none_eq2(H,B,D)) && ((El>=Fl&&El>=Hl) || fullsame(E,I)) && any_eq3(E,C,G,I) && ((El<Fl&&El<Hl) || none_eq2(I,H,F) || notsame(E,R) || notsame(E,S)) ) M=admixX(E,F,H,I,G,D,A,B,C,S,R);
|
||||
// Pattern-based blending rules
|
||||
bool same_B_D = same(B,D);
|
||||
bool same_B_F = same(B,F);
|
||||
bool same_H_D = same(H,D);
|
||||
bool same_H_F = same(H,F);
|
||||
bool same_E_A = same(E,A);
|
||||
bool same_E_C = same(E,C);
|
||||
bool same_E_G = same(E,G);
|
||||
bool same_E_I = same(E,I);
|
||||
|
||||
// Scorpion tail pattern (handles thin diagonal features)
|
||||
if ((notsame(E,F) && all_eq2(E,C,I)&&fullsame(E,D)&&fullsame(D,Q) && fullsame(F,B)&&fullsame(B,H)) && notsame(F,src(srcX+3,srcY))) {K=admixK(F,K); M=admixK(F,M);}
|
||||
if ((notsame(E,D) && all_eq2(E,A,G)&&fullsame(E,F)&&fullsame(F,R) && fullsame(D,B)&&fullsame(B,H)) && notsame(D,src(srcX-3,srcY))) {J=admixK(D,J); L=admixK(D,L);}
|
||||
if ((notsame(E,H) && all_eq2(E,G,I)&&fullsame(E,B)&&fullsame(B,P) && fullsame(H,D)&&fullsame(D,F)) && notsame(H,src(srcX,srcY+3))) {L=admixK(H,L); M=admixK(H,M);}
|
||||
if ((notsame(E,B) && all_eq2(E,A,C)&&fullsame(E,H)&&fullsame(H,S) && fullsame(B,D)&&fullsame(D,F)) && notsame(B,src(srcX,srcY-3))) {J=admixK(B,J); K=admixK(B,K);}
|
||||
// Rule 1: Corner blending (X-pattern)
|
||||
if ( (same_B_D && none_eq2(D,H,F) && none_eq2(B,H,F)) && ((El>=Dl&&El>=Bl) || fullsame(E,A)) && (same_E_A||same_E_C||same_E_G) && ((El<Dl&&El<Bl) || none_eq2(A,D,B) || notsame(E,P) || notsame(E,Q)) ) J=admixX(E,D,B,A,C,F,I,H,G,P,Q);
|
||||
if ( (same_B_F && none_eq2(B,D,H) && none_eq2(F,D,H)) && ((El>=Bl&&El>=Fl) || fullsame(E,C)) && (same_E_A||same_E_C||same_E_I) && ((El<Bl&&El<Fl) || none_eq2(C,B,F) || notsame(E,P) || notsame(E,R)) ) K=admixX(E,F,B,C,A,D,G,H,I,P,R);
|
||||
if ( (same_H_D && none_eq2(H,F,B) && none_eq2(D,F,B)) && ((El>=Hl&&El>=Dl) || fullsame(E,G)) && (same_E_A||same_E_G||same_E_I) && ((El<Hl&&El<Dl) || none_eq2(G,H,D) || notsame(E,S) || notsame(E,Q)) ) L=admixX(E,D,H,G,I,F,C,B,A,S,Q);
|
||||
if ( (same_H_F && none_eq2(F,B,D) && none_eq2(H,B,D)) && ((El>=Fl&&El>=Hl) || fullsame(E,I)) && (same_E_C||same_E_G||same_E_I) && ((El<Fl&&El<Hl) || none_eq2(I,H,F) || notsame(E,R) || notsame(E,S)) ) M=admixX(E,F,H,I,G,D,A,B,C,S,R);
|
||||
|
||||
// Anti-aliasing for cross patterns (smooths jagged edges)
|
||||
if ( (Bl<El) && full_eq3(E,G,H,I) && same(E,S) && none_eq4(E,A,D,C,F) ) {J=admixC(D,B,J); K=admixC(B,F,K);} // Top
|
||||
if ( (Hl<El) && full_eq3(E,A,B,C) && same(E,P) && none_eq4(E,D,G,I,F) ) {L=admixC(D,H,L); M=admixC(F,H,M);} // Bottom
|
||||
if ( (Fl<El) && full_eq3(E,A,D,G) && same(E,Q) && none_eq4(E,B,C,I,H) ) {K=admixC(B,F,K); M=admixC(F,H,M);} // Right
|
||||
if ( (Dl<El) && full_eq3(E,C,F,I) && same(E,R) && none_eq4(E,B,A,G,H) ) {J=admixC(D,B,J); L=admixC(D,H,L);} // Left
|
||||
|
||||
// L-shaped slope handling (2:1 slopes)
|
||||
if (notsame(H,B)) {
|
||||
// Rule 2: K-pattern (Scorpion tail)
|
||||
if (notsame(E,F) && same_E_C&&same_E_I&&fullsame(E,D)&&fullsame(D,Q) && fullsame(F,B)&&fullsame(B,H) && notsame(F,src(srcX+3,srcY)) ) {K=admixK(F,K); M=admixK(F,M);}
|
||||
if (notsame(E,D) && same_E_A&&same_E_G&&fullsame(E,F)&&fullsame(F,R) && fullsame(D,B)&&fullsame(B,H) && notsame(D,src(srcX-3,srcY)) ) {J=admixK(D,J); L=admixK(D,L);}
|
||||
if (notsame(E,H) && same_E_G&&same_E_I&&fullsame(E,B)&&fullsame(B,P) && fullsame(H,D)&&fullsame(D,F) && notsame(H,src(srcX,srcY+3)) ) {L=admixK(H,L); M=admixK(H,M);}
|
||||
if (notsame(E,B) && same_E_A&&same_E_C&&fullsame(E,H)&&fullsame(H,S) && fullsame(B,D)&&fullsame(D,F) && notsame(B,src(srcX,srcY-3)) ) {J=admixK(B,J); K=admixK(B,K);}
|
||||
|
||||
|
||||
// Rule 3: Cross pattern
|
||||
if ( (Bl<El) && full_eq3(E,G,H,I) && same(E,S) && none_eq4(E,A,D,C,F) )
|
||||
{J=admixC(D,B,J); K=admixC(B,F,K);} // Top
|
||||
if ( (Hl<El) && full_eq3(E,A,B,C) && same(E,P) && none_eq4(E,D,G,I,F) )
|
||||
{L=admixC(D,H,L); M=admixC(F,H,M);} // Bottom
|
||||
if ( (Fl<El) && full_eq3(E,A,D,G) && same(E,Q) && none_eq4(E,B,C,I,H) )
|
||||
{K=admixC(B,F,K); M=admixC(F,H,M);} // Right
|
||||
if ( (Dl<El) && full_eq3(E,C,F,I) && same(E,R) && none_eq4(E,B,A,G,H) )
|
||||
{J=admixC(D,B,J); L=admixC(D,H,L);} // Left
|
||||
|
||||
|
||||
// L - type
|
||||
|
||||
if (notsame(H,B)) {
|
||||
|
||||
// E over 2:1 ◢ or -2:1 ◣
|
||||
if (notsame(H,A) && notsame(H,E) && notsame(H,C)) {
|
||||
|
||||
// Ⓐ B C .
|
||||
// Q D 🄴 🅵 🆁
|
||||
// 🅶 🅷 I
|
||||
if (full_eq3(H,G,F,R) && none_eq2(H,D,src(srcX+2,srcY-1))) L=admixL(M,L);
|
||||
|
||||
// . A B Ⓒ
|
||||
// 🆀 🅳 🄴 F R
|
||||
// G 🅷 🅸
|
||||
if (full_eq3(H,I,D,Q) && none_eq2(H,F,src(srcX-2,srcY-1))) M=admixL(L,M);
|
||||
// Ⓐ B C .
|
||||
// Q D 🄴 🅵 🆁
|
||||
// 🅶 🅷 I
|
||||
if (none_eq2(H,D,src(srcX+2,srcY-1))) {
|
||||
// Extend the original rule: incorporate the comparison of adjacent pixels in the third step to ensure that secondary mixing does not occur.
|
||||
if (full_eq3(H,G,F,R)) L=admixL(M,L,H);
|
||||
|
||||
// Extension of the New Rule: New Gradual Edge Morphology Extraction
|
||||
// F -> M
|
||||
else if (!same_H_F && notsame(F,I) && all_eq3(E,C,B,D) && same(F,G) && same(R,H) && !same(E,F) && !same(E,H)) M=unpackUnorm4x8(F);
|
||||
}
|
||||
|
||||
|
||||
// . A B Ⓒ
|
||||
// 🆀 🅳 🄴 F R
|
||||
// G 🅷 🅸
|
||||
if (none_eq2(H,F,src(srcX-2,srcY-1))) {
|
||||
|
||||
if (full_eq3(H,I,D,Q)) M=admixL(L,M,H);
|
||||
// D -> L
|
||||
else if (!same_H_D && notsame(D,G) && all_eq3(E,A,B,F) && same(D,I) && same(Q,H) && !same(E,D) && !same(E,H)) L=unpackUnorm4x8(D);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// E under 2:1 (◥) -2:1 (◤)
|
||||
if (notsame(B,I) && notsame(B,G) && notsame(B,E)) {
|
||||
|
||||
// 🅰️ 🅱 C
|
||||
// Q D 🄴 🅵 🆁
|
||||
// Ⓖ H I .
|
||||
if (full_eq3(B,A,F,R) && none_eq2(B,D,src(srcX+2,srcY+1))) J=admixL(K,J);
|
||||
|
||||
// A 🅱 🅲
|
||||
// 🆀 🅳 🄴 F R
|
||||
// . G H Ⓘ
|
||||
if (full_eq3(B,C,D,Q) && none_eq2(B,F,src(srcX-2,srcY+1))) K=admixL(J,K);
|
||||
}
|
||||
// 🅰️🅱C
|
||||
// Q D 🄴 🅵 🆁
|
||||
// Ⓖ H I .
|
||||
if (none_eq2(B,D,src(srcX+2,srcY+1))) {
|
||||
|
||||
if (full_eq3(B,A,F,R)) J=admixL(K,J,B);
|
||||
// F -> K
|
||||
else if (!same_B_F && notsame(C,F) && all_eq3(E,D,H,I) && same(A,F) && same(B,R) && !same(E,B) && !same(E,F)) K=unpackUnorm4x8(F);
|
||||
}
|
||||
|
||||
|
||||
// A 🅱🅲
|
||||
// 🆀 🅳 🄴 F R
|
||||
// . G H Ⓘ
|
||||
if (none_eq2(B,F,src(srcX-2,srcY+1))) {
|
||||
|
||||
if (full_eq3(B,C,D,Q)) K=admixL(J,K,B);
|
||||
// D -> J
|
||||
else if (!same_B_D && notsame(A,D) && all_eq3(E,F,G,H) && same(B,Q) && same(C,D) && !same(E,B) && !same(E,D)) J=unpackUnorm4x8(D);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (notsame(F,D)) {
|
||||
|
||||
|
||||
|
||||
if (notsame(D,I) && notsame(D,E) && notsame(D,C)) {
|
||||
|
||||
// 🅰B Ⓒ
|
||||
// Q 🅳 🄴 F R
|
||||
// G 🅷 I
|
||||
// 🆂 .
|
||||
if (full_eq3(D,A,H,S) && none_eq2(D,B,src(srcX+1,srcY+2))) J=admixL(L,J);
|
||||
// 🅰B Ⓒ
|
||||
// Q 🅳 🄴 F R
|
||||
// G 🅷 I
|
||||
// 🆂 .
|
||||
if (none_eq2(D,B,src(srcX+1,srcY+2))) {
|
||||
|
||||
if (full_eq3(D,A,H,S)) J=admixL(L,J,D);
|
||||
// H -> L
|
||||
else if (!same_H_D && notsame(G,H) && all_eq3(E,B,F,I) && same(A,H) && same(D,S) && !same(E,D) && !same(E,H)) L=unpackUnorm4x8(H);
|
||||
}
|
||||
|
||||
// 🅿 .
|
||||
// A 🅱 C
|
||||
// Q 🅳 🄴 F R
|
||||
// 🅶 H Ⓘ
|
||||
if (full_eq3(D,G,B,P) && none_eq2(D,H,src(srcX+1,srcY-2))) L=admixL(J,L);
|
||||
}
|
||||
// 🅿.
|
||||
// A 🅱C
|
||||
// Q 🅳 🄴 F R
|
||||
// 🅶 H Ⓘ
|
||||
if (none_eq2(D,H,src(srcX+1,srcY-2))) {
|
||||
|
||||
if (full_eq3(D,G,B,P)) L=admixL(J,L,D);
|
||||
// B -> J
|
||||
else if (!same_B_D && notsame(B,A) && all_eq3(E,C,F,H) && same(P,D) && same(B,G) && !same(E,B) && !same(E,D)) J=unpackUnorm4x8(B);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (notsame(F,E) && notsame(F,A) && notsame(F,G)) {
|
||||
|
||||
// Ⓐ B 🅲
|
||||
// Q D 🄴 🅵 R
|
||||
// G 🅷 I
|
||||
// . 🆂
|
||||
if (full_eq3(F,C,H,S) && none_eq2(F,B,src(srcX-1,srcY+2))) K=admixL(M,K);
|
||||
// Ⓐ B 🅲
|
||||
// Q D 🄴 🅵 R
|
||||
// G 🅷 I
|
||||
// . 🆂
|
||||
if (none_eq2(F,B,src(srcX-1,srcY+2))) {
|
||||
|
||||
if (full_eq3(F,C,H,S)) K=admixL(M,K,F);
|
||||
// H -> M
|
||||
else if (!same_H_F && notsame(H,I) && all_eq3(E,B,D,G) && same(C,H) && same(F,S) && !same(E,F) && !same(E,H)) M=unpackUnorm4x8(H);
|
||||
}
|
||||
|
||||
// . 🅿
|
||||
// A 🅱C
|
||||
// Q D 🄴 🅵 R
|
||||
// Ⓖ H 🅸
|
||||
if (none_eq2(F,H,src(srcX-1,srcY-2))) {
|
||||
|
||||
if (full_eq3(F,I,B,P)) M=admixL(K,M,F);
|
||||
// B -> K
|
||||
else if (!same_B_F && notsame(B,C) && all_eq3(E,A,D,H) && same(P,F) && same(B,I) && !same(E,B) && !same(E,F)) K=unpackUnorm4x8(B);
|
||||
}
|
||||
|
||||
// . 🅿
|
||||
// A 🅱 C
|
||||
// Q D 🄴 🅵 R
|
||||
// Ⓖ H 🅸
|
||||
if (full_eq3(F,I,B,P) && none_eq2(F,H,src(srcX-1,srcY-2))) M=admixL(K,M);
|
||||
}
|
||||
} // F !== D
|
||||
} // not constant
|
||||
// Write 2x2 upscaled pixels
|
||||
|
||||
// Write four pixels at once.
|
||||
ivec2 destXY = ivec2(xy) * 2;
|
||||
writeColorf(destXY, J);
|
||||
writeColorf(destXY + ivec2(1, 0), K);
|
||||
|
||||
Reference in New Issue
Block a user