#version 330 core
out vec3 FragColor;
in vec3 PosWrld;

uniform float rtnStepSize;
uniform samplerCube envMapCube;
uniform float kernel_5x5[25];
uniform int lod_smpl;

void main(){		
    vec3 dir_n  = normalize( PosWrld );
    float theta = atan( dir_n.z, dir_n.x );

    vec3 right_n = vec3( cos( theta - 1.570796327 ), 0.0, sin( theta - 1.570796327 ) );
    vec3 up_n    = cross( right_n, dir_n );

    float Ux   = up_n.x;
    float Uy   = up_n.y;
    float Uz   = up_n.z;
    float Ux2  = Ux * Ux;
    float Uy2  = Uy * Uy;
    float Uz2  = Uz * Uz;
    float UxUy = Ux * Uy;
    float UxUz = Ux * Uz;
    float UyUz = Uy * Uz;

    float Rx   = right_n.x;
    float Rz   = right_n.z;
    float Rx2  = Rx * Rx;
    float Rz2  = Rz * Rz;
    float RxRz = Rx * Rz;

    vec3 color = vec3( 0.0, 0.0, 0.0 );

    for( int rtn_lr = -2; rtn_lr <= 2; rtn_lr++ ){
        float angle_lr   = rtnStepSize * float(rtn_lr);
        float cos_lr     = cos( angle_lr );
        float sin_lr     = sin( angle_lr );
        float oneMcos_lr = 1.0-cos_lr;

        mat3 rotationMatrix_left_right = mat3(
            vec3( cos_lr + Ux2*oneMcos_lr,      UxUy*oneMcos_lr + Uz*sin_lr,  UxUz*oneMcos_lr - Uy*sin_lr ),
            vec3( UxUy*oneMcos_lr - Uz*sin_lr,  cos_lr + Uy2*oneMcos_lr,      UyUz*oneMcos_lr + Ux*sin_lr ),
            vec3( UxUz*oneMcos_lr + Uy*sin_lr,  UyUz*oneMcos_lr - Ux*sin_lr,  cos_lr + Uz2*oneMcos_lr     )
        );

        vec3 dir_smpl_lr = rotationMatrix_left_right * dir_n;

        int m = (rtn_lr + 2)*5;

        for( int rtn_ud = -2; rtn_ud <= 2; rtn_ud++ ){
            float angle_ud   = rtnStepSize * float(rtn_ud);
            float cos_ud     = cos( angle_ud );
            float sin_ud     = sin( angle_ud );
            float oneMcos_ud = 1.0-cos_ud;

            mat3 rotationMatrix_up_down = mat3(
                vec3( cos_ud + Rx2*oneMcos_ud,  Rz*sin_ud,  RxRz*oneMcos_ud         ),
                vec3( -Rz*sin_ud,               cos_ud,     Rx*sin_ud               ),
                vec3( RxRz*oneMcos_ud,          -Rx*sin_ud, cos_ud + Rz2*oneMcos_ud )
            );

            vec3 dir_smpl = rotationMatrix_up_down * dir_smpl_lr;

            color += textureLod( envMapCube, dir_smpl, lod_smpl ).rgb * kernel_5x5[ m + rtn_ud + 2 ];
        }
    }

    FragColor = color;
}