
/*
  2xSaI GLSL shader

           - Copyright (C) 2007 guest(r) - guest.r@gmail.com

           - License: GNU-GPL

           - Enhanced by VerGreeneyes (10.5.2007)

           - Experimental version - modified color "equality"
           
           - Some offset tweaks by guest(r) (3.11.2007)


  The 2xSaI algorithm

           - Copyright (c) 1999-2001 by Derek Liauw Kie Fa.
*/

const float th = .0625; // 2 * 1/2^5 tolerance (2 singletons in RGB555)
const vec4 dt = vec4(65536.,256.,1.,0.);
const vec4 dp = vec4(1.,1.,1.,0.);
const vec2 OGL2Size = vec2(1024.0,512.0);
const vec2 OGL2InvSize = vec2(0.0009765625,0.001953125);

uniform sampler2D OGL2Texture;

#define reduce(color)(dot(color,dt))

float GET_RESULT(float A,float B,float C,float D)
{
    return float(A != C && A != D && B == C && B == D)-float(A == C && A == D);
}

void main()
{

    // Calculating texel coordinates

    vec2 OGL2Pos = gl_TexCoord[0].xy*OGL2Size,
         fp = fract(OGL2Pos),
         g1 = vec2( OGL2InvSize.x,OGL2InvSize.y),
         g2 = vec2(-OGL2InvSize.x,OGL2InvSize.y);

    if(fp.x >= .5 && fp.y < .5) g2=-g2;

    vec2 pC4 = floor(OGL2Pos)/OGL2Size,
         g3 = .5*(g1-g2), pC8 = pC4+g1;


    // Reading the texels

    vec4 C0 = texture2D(OGL2Texture,pC4-g1      ),
         C1 = texture2D(OGL2Texture,pC4-g2-g3   ),
         C2 = texture2D(OGL2Texture,pC4-g2      ),
         C3 = texture2D(OGL2Texture,pC4-g3      ),
         C4 = texture2D(OGL2Texture,pC4         ),
         C5 = texture2D(OGL2Texture,pC4+g3      ),
         C6 = texture2D(OGL2Texture,pC4+g2      ),
         C7 = texture2D(OGL2Texture,pC8-g3      ),
         C8 = texture2D(OGL2Texture,pC8         ),
         D0 = texture2D(OGL2Texture,pC4+2.*g2+g3),
         D1 = texture2D(OGL2Texture,pC8+g2      ),
         D2 = texture2D(OGL2Texture,pC8+g1-g3   ),
         D4 = texture2D(OGL2Texture,pC8-g2      ),
         D5 = texture2D(OGL2Texture,pC8+g3      ),
         p10,p11;

    float c0 = reduce(C0),c1 = reduce(C1),c2 = reduce(C2),c3 = reduce(C3),
          c4 = reduce(C4),c5 = reduce(C5),c6 = reduce(C6),c7 = reduce(C7),
          c8 = reduce(C8),d0 = reduce(D0),d1 = reduce(D1),d2 = reduce(D2),
          d4 = reduce(D4),d5 = reduce(D5);

    /*              SaI code               */
    /*  Copied from the Dosbox source code        */
    /*  Copyright (C) 2002-2007  The DOSBox Team  */
    /*  License: GNU-GPL                          */
    /*  Adapted by guest(r) on 20.4 and 9.5. 2007 */
    /*  and VerGreeneyes (10.5.2007)              */


    float dif1 = dot(abs(C4-C8),dp), dif2 = dot(abs(C5-C7),dp);

    if(dif1 <= th)
    {
        if(dif2 > th)
        {
            p10 = (c4 == c3 && c7 == d2 || c4 == c5 && c4 == c6 && c3 != c7 && c7 == d0) ? C4 : .5*(C4+C7);
            p11 = C4;
        }
        else
        {
            if(c4 == c5) p11 = (p10 = C4);
            else
            {
                float r = GET_RESULT(c4,c5,c3,c1)+GET_RESULT(c4,c5,d5,d2)
                         -GET_RESULT(c5,c4,d4,c2)-GET_RESULT(c5,c4,c6,d1);
                p10 = .5*(C4+C7);
                if(r > 0.) p11 = C4;
                else if(r < 0.) p11 = C5;
                else p11 = .25*(C4+C5+C7+C8);
            }
        }
    }
    else if(dif2 <= th)
    {
        p10 = (c7 == c6 && c4 == c2 || c7 == c3 && c7 == c8 && c4 != c6 && c4 == c0) ? C7 : 0.5*(C4+C7);
        p11 = C5;
    }
    else
    {
        p11 = 0.25*(C4+C5+C7+C8);
        if(c4 == c5 && c4 == c6 && c3 != c7 && c7 == d0) p10 = C4;
        else if(c7 == c3 && c7 == c8 && c4 != c6 && c4 == c0) p10 = C7;
        else p10 = 0.5*(C4+C7);
    }

    // Distributing the final products

    if(fp.x >= .5 && fp.y >= .5) gl_FragColor = p11;
    else if(fp.x >= .5 || fp.y >= .5) gl_FragColor = p10;
    else gl_FragColor = C4;
}