/*
   Lanczos Sharp Shader v 1.0

   Copyright (C) 2018 SimoneT - simone1tarditi@gmail.com

   ColMin and ColMax functions - Copyright (C) 2018 SimoneT

   de Blur - Copyright (C) 2016 guest(r) - guest.r@gmail.com

   colour length and colour distance functions from "Colour metric"

   https://www.compuphase.com/cmetric.htm

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 3
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    
*/

#version 130
#define FIX(c) max(abs(c), 1e-5);

uniform sampler2D OGL2Texture;
uniform vec4 OGL2Size;
uniform vec4 OGL2InvSize;
uniform vec4 OGL2Param;

const float PI = 3.1415926535897932384626433832795;

const   vec4 Size1X  = vec4( 1024.0, 512.0, 0.0009765625, 0.001953125);
const   vec4 Size2X  = vec4( 2048.0, 1024.0, 0.00048828125, 0.0009765625);
const   vec4 Size4X  = vec4( 4096.0, 2048.0, 0.000244140625, 0.00048828125);

vec3 Bilinear( vec2 Coords ) {

	vec2 dim = Coords * Size1X.xy - 0.5;
   
	vec2 fxy = fract(dim);

	vec2 pos = floor(dim)*Size1X.zw;

	vec2 posx  = pos+vec2( Size1X.z,      0.0);
	vec2 posy  = pos+vec2(      0.0, Size1X.w);
	vec2 posxy = pos+vec2( Size1X.z, Size1X.w);

	vec3 C0 = texture(OGL2Texture, pos   ).rgb; 
	vec3 C1 = texture(OGL2Texture, posx  ).rgb;
	vec3 C2 = texture(OGL2Texture, posy  ).rgb;
	vec3 C3 = texture(OGL2Texture, posxy ).rgb;

	vec3 C5 = mix(mix(C0,C1,fxy.x),mix(C2,C3,fxy.x),fxy.y);

	return C5;

}

float clength(vec3 a){

	a *= 255.0;

	float rmean = a.r*0.5;

	a*= a;

	//from https://en.wikipedia.org/wiki/Color_difference

	return sqrt(dot(vec3(2.0,4.0,3.0),a)+rmean*(a.r-a.b)/256.0); 

}

float cdistance(vec3 a, vec3 b){

	a *= 255.0;

	b *= 255.0;

	float rmean = (a.r+b.r)*0.5;

	a = pow(a-b,vec3(2.0));

	//from https://en.wikipedia.org/wiki/Color_difference

	return sqrt(dot(vec3(2.0,4.0,3.0),a)+rmean*(a.r-a.b)/256.0);

}

vec3 ColMin(vec3 a, vec3 b){

	float diff = step(0.0,sign(clength(a)-clength(b)));

	return mix(a,b,diff);

}

vec3 ColMax(vec3 a, vec3 b){

	float diff = step(0.0,sign(clength(a)-clength(b)));

	return mix(b,a,diff);

}

vec3 weight3(float x){

	const float radius = 3.0;
	vec3 sample = FIX(2.0 * PI * vec3(x - 1.5, x - 0.5, x + 0.5));

	// Lanczos3. Note: we normalize outside this function, so no point in multiplying by radius.
	return /*radius **/ sin(sample) * sin(sample / radius) / (sample * sample);
        
}

vec3 pixel(float xpos, float ypos){

	return texture2D(OGL2Texture, vec2(xpos, ypos)).rgb;
        
}

vec3 line(float ypos, vec3 xpos1, vec3 xpos2, vec3 linetaps1, vec3 linetaps2){

	return  pixel(xpos1.r, ypos) * linetaps1.r +
                pixel(xpos1.g, ypos) * linetaps2.r +
                pixel(xpos1.b, ypos) * linetaps1.g +
                pixel(xpos2.r, ypos) * linetaps2.g +
                pixel(xpos2.g, ypos) * linetaps1.b +
                pixel(xpos2.b, ypos) * linetaps2.b;
        
}

vec3 Lanczos(vec2 TexCoord ){

/*
   <!--
   Lanczos (6tap) scaling

   Copyright (C) 2010 Team XBMC
   http://www.xbmc.org
   Copyright (C) 2011 Stefanos A.
   http://www.opentk.com
   Copyright (C) 2011 BlackStar and DOLLS

   This Program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This Program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   -->
   <!--
       From these forum posts:

        http://board.byuu.org/viewtopic.php?p=33597#p33597
        http://board.byuu.org/viewtopic.php?p=34426#p34426
   -->
*/

	//vec2 stepxy = 1.0 / OGL2Size.xy;
	vec2 stepxy = Size1X.zw;
	vec2 pos = TexCoord + stepxy * 0.5;
	vec2 f = fract(pos / stepxy);

	vec3 linetaps1   = weight3(0.5 - f.x * 0.5);
	vec3 linetaps2   = weight3(1.0 - f.x * 0.5);
	vec3 columntaps1 = weight3(0.5 - f.y * 0.5);
	vec3 columntaps2 = weight3(1.0 - f.y * 0.5);

	// make sure all taps added together is exactly 1.0, otherwise some
	// (very small) distortion can occur
	float suml = dot(linetaps1, vec3(1.0)) + dot(linetaps2, vec3(1.0));
	float sumc = dot(columntaps1, vec3(1.0)) + dot(columntaps2, vec3(1.0));
	linetaps1 /= suml;
	linetaps2 /= suml;
	columntaps1 /= sumc;
	columntaps2 /= sumc;
	vec2 xystart = (-2.5 - f) * stepxy + pos;
	vec3 xpos1 = vec3(xystart.x, xystart.x + stepxy.x, xystart.x + stepxy.x * 2.0);
	vec3 xpos2 = vec3(xystart.x + stepxy.x * 3.0, xystart.x + stepxy.x * 4.0, xystart.x + stepxy.x * 5.0);

	vec3 c0 = line(xystart.y                 , xpos1, xpos2, linetaps1, linetaps2) * columntaps1.r +
                  line(xystart.y + stepxy.y      , xpos1, xpos2, linetaps1, linetaps2) * columntaps2.r +
                  line(xystart.y + stepxy.y * 2.0, xpos1, xpos2, linetaps1, linetaps2) * columntaps1.g +
                  line(xystart.y + stepxy.y * 3.0, xpos1, xpos2, linetaps1, linetaps2) * columntaps2.g +
                  line(xystart.y + stepxy.y * 4.0, xpos1, xpos2, linetaps1, linetaps2) * columntaps1.b +
                  line(xystart.y + stepxy.y * 5.0, xpos1, xpos2, linetaps1, linetaps2) * columntaps2.b;

	return clamp(c0,0.0,1.0);

}

//      de Blur code

vec3 deBlur(vec2 texCoord) {

	vec4 Size = Size2X;

	vec2 dx = vec2( Size.z,    0.0);
	vec2 dy = vec2(    0.0, Size.w);
	vec2 g1 = vec2( Size.z, Size.w);
	vec2 g2 = vec2(-Size.z, Size.w);

	vec3 C0 = Bilinear( texCoord-g1 ); 
	vec3 C1 = Bilinear( texCoord-dy );
	vec3 C2 = Bilinear( texCoord-g2 );
	vec3 C3 = Bilinear( texCoord-dx );
	vec3 C4 =  Lanczos( texCoord    );
	vec3 C5 = Bilinear( texCoord+dx );
	vec3 C6 = Bilinear( texCoord+g2 );
	vec3 C7 = Bilinear( texCoord+dy );
	vec3 C8 = Bilinear( texCoord+g1 );

	vec3 mn1 = ColMin(ColMin(C0,C1),C2);
	vec3 mn2 = ColMin(ColMin(C3,C4),C5);
	vec3 mn3 = ColMin(ColMin(C6,C7),C8);
	     mn1 = ColMin(ColMin(mn1,mn2),mn3);

	vec3 mx1 = ColMax(ColMax(C0,C1),C2);
	vec3 mx2 = ColMax(ColMax(C3,C4),C5);
	vec3 mx3 = ColMax(ColMax(C6,C7),C8);
 	     mx1 = ColMax(ColMax(mx1,mx2),mx3);

	float dif1 = cdistance(C4,mn1);
	float dif2 = cdistance(C4,mx1);
 
	float filterparam = 6.0; // de Blur control

	dif1=pow(dif1,filterparam);
	dif2=pow(dif2,filterparam);
 
	float dif3=dif1+dif2; 

	vec3 C9 = (dif1*mx1 + dif2*mn1)/dif3;

	if (dif3 == 0.0 ) { C9 = C4; }
 
	return C9;

}

void main()
{

	gl_FragColor.rgb = deBlur(gl_TexCoord[0].xy);
}
