/* Shader for application of a spherical projection of textures during drawing.
 *
 * (C)2010-2011 by Ingmar Schneider and Mario Kleiner.
 * Licensed to you under MIT license.
 *
 * This is version 2, with improved math by Ingmar Schneider to fix the
 * problems with central magnification and anisotropy.
 *
 */

#extension GL_ARB_texture_rectangle : enable

uniform int           doFilter;
uniform sampler2DRect Image;
uniform vec2          inSize;
uniform vec2          inOffset;
uniform vec2          outSize;

/* Width of the projection area at a distance R in cm */
uniform float         Wflat;

/* Radius of the used spherical screen in cm */
uniform float         R;

void main()
{
    vec4 texcolor, tl, tr, bl, br;

    /* Get wanted output pixel coordinates for which we should remap:  */
    /* texoutpos is the location of the output pixel for which we need */
    /* to compute the final remapped color value                       */
    vec2 texoutpos = (gl_TexCoord[0].st) - vec2(0.5, 0.5);

    /* Apply 2D offset to output pixel location, as well as a 2D rescaling: */
    /* This to account for situations where not the full display area of    */
    /* display device is used. */
    texoutpos = clamp(texoutpos, vec2(0.0), outSize);

    /* Geometric remapping/warping: Recompute and assign modified components */
    /* of texoutpos, based on texinpos and display geometry:                 */    
    float Wunits = Wflat / R;
    vec2 UnitsPerPixel = vec2(Wunits)/ outSize;
    
    /* Centering */
    texoutpos = (texoutpos - ((outSize+1.0)/2.0)) * UnitsPerPixel;
    
    /* Unwarping */
    texoutpos = texoutpos / sqrt(1.0 - pow(abs(texoutpos.x), 2.0) - pow(abs(texoutpos.y), 2.0));
    
    /* Retransformation to image coordinates */
    texoutpos = (texoutpos/UnitsPerPixel) + ((outSize+1.0)/2.0);
            
    /* Offsetting */
    vec2 texinpos = inOffset + texoutpos;

    /* texinpos now contains the location of the final input image pixel to read   */
    /* for creation of the final output color pixel. This value may be fractional. */

    /* Need to filter input image texture ourselves? */
    if (doFilter > 0) {
        /* Need to do our own bilinear filtering: Get colors of four nearest */
        /* neighbour texels for given non-integral, fractional 'texinpos':   */
        tl=texture2DRect(Image, floor(texinpos));
        tr=texture2DRect(Image, floor(texinpos) + vec2(1.0, 0.0));
        bl=texture2DRect(Image, floor(texinpos) + vec2(0.0, 1.0));
        br=texture2DRect(Image, floor(texinpos) + vec2(1.0, 1.0));

        /* Perform weighted linear interpolation -- bilinear interpolation of the 4: */
        tl=mix(tl,tr,fract(texinpos.x));
        bl=mix(bl,br,fract(texinpos.x));
        texcolor = mix(tl, bl, fract(texinpos.y));
    }
    else
    {
        /* Standard case: Hardware does bilinear filtering: */
        texcolor = texture2DRect(Image, texinpos);
    }

    /* Set all undefined (outside input image) pixels to black background color. */
    if (texinpos.x < 0.0 || texinpos.x >= inSize.x || texinpos.y < 0.0 || texinpos.y >= inSize.y || texinpos.x != texinpos.x || texinpos.y != texinpos.y) {
        gl_FragColor = vec4(0.0);
    }
    else
    {
        /* Multiply filtered texcolor with incoming fragment color (GL_MODULATE emulation): */
        /* Assign result as output fragment color: */
        gl_FragColor = texcolor * gl_Color;
    }
}
