/*
   SimoneT mixed 3D - 2D games Shader v 1.12 WIP

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

   part of code taken from "Directional Cubic Convolution Interpolation"
   created by Dengwen Zhou and Xiaoliu Shen.

   https://en.wikipedia.org/wiki/Directional_Cubic_Convolution_Interpolation 

   deblur code taken from "27.3 Shock Filtering: A Method for Deblurring Images"
   
   http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter27.html

   Copyright © 2005 by NVIDIA Corporation.

   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
   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.
    
*/

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

const   vec2 Size1D    = vec2( 1024.0, 512.0 );
const   vec2 InvSize1D = vec2( 0.0009765625, 0.001953125 );

const   vec2 Size2D    = vec2( 2048.0, 1024.0 );
const   vec2 InvSize2D = vec2( 0.00048828125, 0.0009765625 );

const   vec2 Size3D    = vec2( 4096.0, 2048.0 );
const   vec2 InvSize3D = vec2( 0.000244140625, 0.00048828125 );

const   vec3 one       = vec3( 255.0 );

const   vec3 ones      = vec3(1.0, 1.0, 1.0);

	vec2 OGL2Size2D= Size2D * OGL2Size.zw;
	vec2 OGL2Size3D= Size3D * OGL2Size.zw;

float Cdistance(vec3 c1, vec3 c2){

	     c1  = pow(c1,vec3(2.4));

	     c2  = pow(c2,vec3(2.4));

	vec3 c3  = abs(c1 - c2);

	return dot(c3,one);

}

float detect3d( vec2 texCoords, vec2 texSize, vec2 shift ){

	vec2 pos = (floor(texCoords*texSize)+0.5)*shift;

	vec2 swirl = fract((texCoords*texSize)*0.5);

	shift.x = ( swirl.x < 0.5 ) ? ( shift.x ) : ( -shift.x ) ;
	shift.y = ( swirl.y < 0.5 ) ? ( shift.y ) : ( -shift.y ) ;

	vec3 a = texture2D(OGL2Texture, pos                        ).rgb;
	vec3 b = texture2D(OGL2Texture, pos + vec2( shift.x, 0.0 ) ).rgb;
	vec3 c = texture2D(OGL2Texture, pos + vec2( 0.0, shift.y ) ).rgb;
	vec3 d = texture2D(OGL2Texture, pos + shift                ).rgb; 

	float e;

	( a == b && b == c && c == d ) ? ( e = 0.0 ) : ( e = 1.0 ) ;

	return e;

}

vec3 Interpolate( vec3 a, vec3 b, vec3 c ) {

	return ( a + 2.0 * b + c ) * 0.25 ;

}

vec3 Diagonal( vec2 coord, vec2 texSize, vec2 shift, vec2 newsize ) {

	vec2 TexCoord = (floor(coord*texSize))*shift;

	vec2 shiftx = vec2(shift.x,0.0);
	vec2 shifty = vec2(0.0,shift.y);

	TexCoord = TexCoord - shift;
	vec3 C00 = texture(OGL2Texture, TexCoord).rgb;
	TexCoord = TexCoord + shiftx;
	vec3 C01 = texture(OGL2Texture, TexCoord).rgb;
	TexCoord = TexCoord + shiftx;
	vec3 C02 = texture(OGL2Texture, TexCoord).rgb;
	TexCoord = TexCoord + shiftx;
	vec3 C03 = texture(OGL2Texture, TexCoord).rgb;

	TexCoord = TexCoord + shifty;
	vec3 C08 = texture(OGL2Texture, TexCoord).rgb;
	TexCoord = TexCoord - shiftx;
	vec3 C07 = texture(OGL2Texture, TexCoord).rgb;
	TexCoord = TexCoord - shiftx;
	vec3 C06 = texture(OGL2Texture, TexCoord).rgb;
	TexCoord = TexCoord - shiftx;
	vec3 C05 = texture(OGL2Texture, TexCoord).rgb;

	TexCoord = TexCoord + shifty;
	vec3 C10 = texture(OGL2Texture, TexCoord).rgb;
	TexCoord = TexCoord + shiftx;
	vec3 C11 = texture(OGL2Texture, TexCoord).rgb;
	TexCoord = TexCoord + shiftx;
	vec3 C12 = texture(OGL2Texture, TexCoord).rgb;
	TexCoord = TexCoord + shiftx;
	vec3 C13 = texture(OGL2Texture, TexCoord).rgb;

	TexCoord = TexCoord + shifty;
	vec3 C18 = texture(OGL2Texture, TexCoord).rgb;
	TexCoord = TexCoord - shiftx;
	vec3 C17 = texture(OGL2Texture, TexCoord).rgb;
	TexCoord = TexCoord - shiftx;
	vec3 C16 = texture(OGL2Texture, TexCoord).rgb;
	TexCoord = TexCoord - shiftx;
	vec3 C15 = texture(OGL2Texture, TexCoord).rgb;

	float C02C08 = Cdistance(C02,C08);
	float C01C07 = Cdistance(C01,C07);
	float C07C13 = Cdistance(C07,C13);
	float C00C06 = Cdistance(C00,C06);
	float C06C12 = Cdistance(C06,C12);
	float C12C18 = Cdistance(C12,C18);
	float C05C11 = Cdistance(C05,C11);
	float C11C17 = Cdistance(C11,C17);
	float C10C16 = Cdistance(C10,C16);

	float C01C05 = Cdistance(C01,C05);
	float C02C06 = Cdistance(C02,C06);
	float C06C10 = Cdistance(C06,C10);
	float C03C07 = Cdistance(C03,C07);
	float C07C11 = Cdistance(C07,C11);
	float C11C15 = Cdistance(C11,C15);
	float C08C12 = Cdistance(C08,C12);
	float C12C16 = Cdistance(C12,C16);
	float C13C17 = Cdistance(C13,C17);

	vec4 d01 = vec4( C01C07 + C00C06 + C06C12 + C05C11,
			 C02C08 + C01C07 + C07C13 + C06C12,
			 C06C12 + C05C11 + C11C17 + C10C16,
			 C07C13 + C06C12 + C12C18 + C11C17 );

	vec4 d02 = vec4( C01C05 + C02C06 + C06C10 + C07C11,
			 C02C06 + C03C07 + C07C11 + C08C12,
			 C06C10 + C07C11 + C11C15 + C12C16,
			 C07C11 + C08C12 + C12C16 + C13C17 );

	vec4 w01 = 1.0 / ( 1.0 + d01 );
	vec4 w02 = 1.0 / ( 1.0 + d02 );
	vec4 w03 = 1.0 / ( w01 + w02 );

	vec4 weight01 = w01 * w03;
	vec4 weight02 = w02 * w03;

	vec3 sum0 = Interpolate( C00, C06, C12 ) * weight01.x + Interpolate( C02, C06, C10 ) * weight02.x; 

	vec3 sum1 = Interpolate( C01, C07, C13 ) * weight01.y + Interpolate( C03, C07, C11 ) * weight02.y;

	vec3 sum2 = Interpolate( C05, C11, C17 ) * weight01.z + Interpolate( C07, C11, C15 ) * weight02.z;

	vec3 sum3 = Interpolate( C06, C12, C18 ) * weight01.w + Interpolate( C08, C12, C16 ) * weight02.w;

	vec2 frac = fract(vec2(gl_TexCoord[1].x,1.0-gl_TexCoord[1].y)*newsize);

	return mix(mix(sum0,sum1,frac.x),mix(sum2,sum3,frac.x),frac.y);
 
}

vec3 deblur( vec2 coord, vec2 texSize, vec2 shift, vec2 newsize ) {

	vec3 curCol   = ( Diagonal( coord, texSize, shift, newsize ) );
	vec3 downCol  = ( Diagonal( coord-vec2(0.0,shift.y), texSize, shift, newsize ) );
	vec3 upCol    = ( Diagonal( coord+vec2(0.0,shift.y), texSize, shift, newsize ) );
	vec3 leftCol  = ( Diagonal( coord-vec2(shift.x,0.0), texSize, shift, newsize ) );
	vec3 rightCol = ( Diagonal( coord+vec2(shift.x,0.0), texSize, shift, newsize ) );

  	vec3 Convexity = 4.0 * curCol - rightCol - leftCol - upCol - downCol;

  	vec2 diffusion  = vec2(dot((rightCol - leftCol) * Convexity, ones),

                               dot((upCol    - downCol) * Convexity, ones));

  	     diffusion *= 0.5/(length(diffusion) + 0.00001);

  	     curCol  += (diffusion.x > 0.0 ? diffusion.x * rightCol : -diffusion.x*  leftCol) + 
		        (diffusion.y > 0.0 ? diffusion.y * upCol    : -diffusion.y * downCol);


	return curCol/(1.0 + dot(abs(diffusion), ones.xy));

}


void main()
{

	float e  = detect3d( gl_TexCoord[0].xy, Size2D, InvSize2D );

	vec3 temp = ( e < 1.0 ) ? (   deblur( gl_TexCoord[0].xy, Size2D, InvSize2D, OGL2Size2D ) ): 
				  ( Diagonal( gl_TexCoord[0].xy, Size3D, InvSize3D, OGL2Size3D ) );

	gl_FragColor.rgb = temp;

}
