varying vec2 texcoord0;
vec4 pos;
float u, v, x, y, z;
varying float r, theta, s;
float lambda, phi;
float extent, scale, vis_mode, center_lambda, center_phi;
varying float zbu,zbv,zblambda,zbr,zbR,zbalpha,zbrho;

void main(void){

    texcoord0 = vec2(gl_MultiTexCoord0);
    pos = gl_Vertex;

    // getting paramters from the interface
    extent = gl_ProjectionMatrix[0].x;
    scale = gl_ProjectionMatrix[1].y;
    vis_mode = gl_ProjectionMatrix[2].z;
    center_lambda = gl_ModelViewMatrix[0].x;
    center_phi = gl_ModelViewMatrix[1].y;

    x = pos.x;
    y = pos.y;
    z = pos.z;

    //Rotation 1: (-center_lambda)-rotation on the xz-plane
    float x_copy = x;
    x = cos(-center_lambda)*x - sin(-center_lambda)*z;
    y = 1.0*y;
    z = sin(-center_lambda)*x_copy + cos(-center_lambda)*z;

    //Rotation 2: (-center_phi)-rotation on the yz-plane
    float y_copy = y;
    x = 1.0*x;
    y = cos(-center_phi)*y - sin(-center_phi)*z;
    z = sin(-center_phi)*y_copy + cos(-center_phi)*z;

    // stereographic projection
    u = 2.0*x/(-z+1.0);
    v = 2.0*y/(-z+1.0);

    // from cartesian to polar coordinates
    r = sqrt(u*u+v*v);
    theta = atan(u,v);

    // scaling the complex plane according to scale specified in the interface
    r *= scale;

    // mapping from polar coordinates to cartesian coordinates
    u = -r*sin(theta);
    v = r*cos(theta);

    // mapping back from the complex plane to the unit sphere
    x = (4.0*u)/(u*u+v*v+4.0);
    y = (4.0*v)/(u*u+v*v+4.0);
    z = (u*u+v*v-4.0)/(u*u+v*v+4.0);

    // mapping back to the equirectangular domain
    lambda = atan(x,-z)/3.1415;
    phi = asin(y)/1.5708;

    // Visualize using specified visualization (remove for timings in the paper! Use only "Perspective" in the paper!)
    if (vis_mode==1.0) { // Moebius
        u = x/(-z);
        v = y/(-z);
        gl_Position = vec4(u/extent,v/extent,z,1.0);
    }
    else if (vis_mode==2.0) // 3D Sphere
        gl_Position = vec4(0.9*x,0.9*y,z,1.0);
    else if (vis_mode==3.0) // Equi-Rectangular
        gl_Position = vec4(lambda,phi,z,1.0);
    else if (vis_mode==4.0) { // Stereographic
        u = 2.f*x/(-z+1);
        v = 2.f*y/(-z+1);
        gl_Position = vec4(u/extent,v/extent,z,1.0);
    }
    else if (vis_mode==5.0) { // Mercator
        u = lambda;
        v = log((1.0/cos(phi)) + tan(phi));
        gl_Position = vec4(u,v,z,1.0);
    }
    else if (vis_mode==6.0) { // Zorin-Barr
        // perspective projection
        zbu = x/(-z);
        zbv = y/(-z);
        // Z-B transformation
        zblambda=0.1;
        zbR=1.0;
        zbalpha=atan(zbv,zbu);
        zbr=sqrt(zbu*zbu+zbv*zbv);
        zbrho=(zblambda*zbr/zbR)+(1.0-zblambda)*(zbR*(sqrt(zbr*zbr+1.0)-1.0))/(zbr*(sqrt(zbR*zbR+1.0)-1.0));
        u=zbrho*cos(zbalpha);
        v=zbrho*sin(zbalpha);
        gl_Position = vec4(u/extent,v/extent,z,1.0);
    }

//    gl_Position = vec4(u/2.0,v/2.0,z,1.0);

}
