--require"glutils.utils"
local function GenerateSeparableGaussKernel(sigma, kernelSize )

    if( (kernelSize % 2) ~= 1 ) then
        assert( false ); -- kernel size must be odd number
    end

    local halfKernelSize = math.floor(kernelSize/2);

    local kernel = {}

    local cPI= math.pi
    local mean     = halfKernelSize;
    local sum      = 0.0;
    for  x = 0, kernelSize - 1 do 
        kernel[x] = math.sqrt( math.exp( -0.5 * (math.pow((x-mean)/sigma, 2.0) + math.pow((mean)/sigma,2.0)) )/ (2 * cPI * sigma * sigma) );
        sum = sum + kernel[x];
    end
	
	--sum = sum + kernel[0] --sumar otra vez este
	
    for  x = 0, kernelSize - 1 do  
        kernel[x] = kernel[x]/sum;
	end
	
    return kernel;

end

local function GetAppropriateSeparableGauss( kernelSize,eps )
    if( (kernelSize % 2) ~= 1 ) then
        assert( false ); -- kernel size must be odd number
    end

    -- Search for sigma to cover the whole kernel size with sensible values (might not be ideal for all cases quality-wise but is good enough for performance testing)
    local epsilon =  ( (eps or 0.02) / kernelSize);
    local searchStep = 1.0;
    local sigma = 1.0;

    while( true ) do
		repeat
        local kernelAttempt = GenerateSeparableGaussKernel( sigma, kernelSize );
		
		local sum      = 0.0;
		for  x = 0, kernelSize - 1 do 
			sum = sum + kernelAttempt[x];
		end
		--sum = sum + kernelAttempt[0]
		print("sum",sum,kernelAttempt[0],sigma)
		
        if( kernelAttempt[0] > epsilon ) then
            if( searchStep > 0.02 ) then
                sigma = sigma - searchStep;
                searchStep = searchStep * 0.1;
                sigma = sigma + searchStep;
                --continue;
				print"continue"
				break
            end
print("sigma",sigma)			
            return kernelAttempt;
        end

        sigma = sigma + searchStep;

        if( sigma > 1000.0 ) then
            assert( false ); -- not tested, preventing infinite loop
        end
		until true
    end

    assert(false)
end

local fragH = [[

precision highp float;
out vec4 FragColor;
//in vec2 vTexCoord;
uniform float w;
//uniform float h;
uniform float mixfac;
//uniform vec4 uRTPixelSizePixelSizeHalf;
uniform sampler2D uTex0;

void main()
{
    vec2 vTexCoord = gl_TexCoord[0].xy;
	vec4 blured = GaussianBlur( uTex0, vTexCoord, vec2( 1.0/w, 0.0 ) );
	vec4 orig = texture( uTex0, vTexCoord );
	FragColor = mix(orig, blured, mixfac);
}
]]

local fragV = [[

precision highp float;
out vec4 FragColor;
//in vec2 vTexCoord;
//uniform float w;
uniform float h;
uniform float mixfac;
//uniform vec4 uRTPixelSizePixelSizeHalf;

uniform sampler2D uTex0;

void main()
{
    vec2 vTexCoord = gl_TexCoord[0].xy;
	vec4 blured = GaussianBlur( uTex0, vTexCoord, vec2( 0.0, 1.0/h ) );
	vec4 orig = texture( uTex0, vTexCoord );
	FragColor = mix(orig, blured, mixfac);
}
]]

local function array2string(arr)
	return table.concat(arr,",\n")
end
local function GenerateGaussShaderKernelWeightsAndOffsets( kernelSize,  eps )

    -- Gauss filter kernel & offset creation
    local inputKernel = GetAppropriateSeparableGauss(kernelSize, eps);

	local sum      = 0.0;
		for  x = 0, kernelSize - 1 do 
			sum = sum + inputKernel[x];
		end
		print(" returned sum",sum,inputKernel[0])
	
    assert( (kernelSize % 2) == 1 );
   assert( ((math.floor(kernelSize/2)+1) % 2) == 0 );

    local oneSideInputs = {};
    for i = math.floor(kernelSize/2), 0,-1 do
        if( i == math.floor(kernelSize/2) ) then
            --oneSideInputs.push_back( (float)inputKernel[i] * 0.5f );
			table.insert(oneSideInputs,inputKernel[i] * 0.5)
        else
            --oneSideInputs.push_back( (float)inputKernel[i] );
			table.insert(oneSideInputs,inputKernel[i])
		end
    end
	
	prtable(inputKernel)
	prtable(oneSideInputs)
	local sum = 0
	for i,v in ipairs(oneSideInputs) do
		sum = sum + v
	end
	print("oneSideInputs sum",sum,sum*2)
	
    assert( (#oneSideInputs % 2) == 0 );
    local numSamples = #oneSideInputs/2;

    local weights = {}

    for i = 0, numSamples - 1 do
        local sum = oneSideInputs[i*2+0 +1] + oneSideInputs[i*2+1+1];
       -- weights.push_back(sum);
		table.insert(weights,sum)
	end

    local offsets = {}

    for i = 0, numSamples - 1 do
        --offsets.push_back( i*2.0f + oneSideInputs[i*2+1] / weights[i] );
		table.insert(offsets, i*2.0 + oneSideInputs[i*2+1 +1] / weights[i + 1])
    end
	
	local sum = 0
	for i,v in ipairs(weights) do
		sum = sum + v
	end
	print("weights sum",sum)
	local gaussfunc = [[
	
	//automatically generated by GenerateGaussFunctionCode in GaussianBlur.h 
	
	vec4 GaussianBlur( sampler2D tex0, vec2 centreUV, vec2 pixelOffset)                                                                           
	{                          
	    vec4 colOut = vec4( 0, 0, 0, 0 );    
		//////////////////////////////////////////////////////////////////////////////////////////////////////;
	    // Kernel width]] .. kernelSize .. [[
	    //
	    const int stepCount = ]]..numSamples..[[;
	    //
	    const float gWeights[stepCount] = float[](
	      ]] ..array2string(weights)..[[
	    );
	    const float gOffsets[stepCount] = float[](
	      ]]..array2string(offsets)..[[
	    );
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////;
	    for( int i = 0; i < stepCount; i++ )
	    {                                 
	        vec2 texCoordOffset = gOffsets[i] * pixelOffset;
	        vec4 col = texture( tex0, centreUV + texCoordOffset ) + texture( tex0, centreUV - texCoordOffset);                                                
	        colOut += gWeights[i] * col;
	    }                        
	    return colOut;
	}
]]		
	prtable(weights,offsets)
	return gaussfunc .. fragH,gaussfunc .. fragV

--[[}                                                                                                                                                                    
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////std::string indent = "    ";

    std::string shaderCode = (forPreprocessorDefine)?(""):("");
    std::string eol = (forPreprocessorDefine)?("\\\n"):("\n");
    if( !forPreprocessorDefine) shaderCode += indent + "//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////;" + eol;
    if( !forPreprocessorDefine) shaderCode += indent + stringFormatA( "// Kernel width %d x %d", kernelSize, kernelSize ) + eol;
    if( !forPreprocessorDefine) shaderCode += indent + "//" + eol;
    shaderCode += indent + stringFormatA( "const int stepCount = %d;", numSamples ) + eol;

    if( !workaroundForNoCLikeArrayInitialization )
    {
        if( !forPreprocessorDefine) shaderCode += indent + "//" + eol;
        shaderCode += indent + "const float gWeights[stepCount] ={" + eol;
        for( int i = 0; i < numSamples; i++ )
            shaderCode += indent + stringFormatA( "   %.5f", weights[i] ) + ((i!=(numSamples-1))?(","):("")) + eol;
        shaderCode += indent + "};"+eol;
        shaderCode += indent + "const float gOffsets[stepCount] ={"+eol;
        for( int i = 0; i < numSamples; i++ )
            shaderCode += indent + stringFormatA( "   %.5f", offsets[i] ) + ((i!=(numSamples-1))?(","):("")) + eol;
        shaderCode += indent + "};" + eol;
    }
    else
    {
        if( !forPreprocessorDefine) shaderCode += indent + "//" + eol;
        shaderCode += indent + "float gWeights[stepCount];" + eol;
        for( int i = 0; i < numSamples; i++ )
            shaderCode += indent + stringFormatA( " gWeights[%d] = %.5f;", i, weights[i] ) + eol;
        shaderCode += indent + eol;
        shaderCode += indent + "float gOffsets[stepCount];"+eol;
        for( int i = 0; i < numSamples; i++ )
            shaderCode += indent + stringFormatA( " gOffsets[%d] = %.5f;", i, offsets[i] ) + eol;
        shaderCode += indent + eol;
    }

    if( !forPreprocessorDefine) shaderCode += indent + "//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////;" + eol;

    return shaderCode;
	--]]
end
--prtable(GenerateGaussShaderKernelWeightsAndOffsets(7))
--print"end gussiankernel gen zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
return GenerateGaussShaderKernelWeightsAndOffsets