var FXBirdieIntroduction = function () {

	FRAME.Module.call( this );

	this.parameters.input = {
		funkyness: 0,
		camera_distance: 2.1508,
		backoff: 0
	};

	var width = renderer.domElement.width;
	var height = renderer.domElement.height;

	var scene = new THREE.Scene();
	var camera = new THREE.OrthographicCamera(window.innerWidth / -2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / -2, -10, 10);
	var quadmaterial;
	var quad;

	this.init = function ( parameters ) {

		this.parameters.input = parameters;
	    var quadgeometry = new THREE.PlaneGeometry(window.innerWidth, window.innerHeight);
	    
	    var maxitertxt = "#define RM_MAX_ITER 20";

		if (parameters.backoff == 2)
		{
	    	maxitertxt = "#define RM_MAX_ITER 3";
		}

		this.quadmaterial = new THREE.ShaderMaterial({
	        uniforms: {
	                iGlobalTime: {
	                	type: "f",
	                	value: 1.0
	                },
	                iResolution: {
	                	type: "v2",
	                	value: new THREE.Vector2(renderer.getContext().drawingBufferWidth, renderer.getContext().drawingBufferHeight),
	                },
	                closed_left_eye: {
	                	type: "f",
	                	value: 0.9
	                },
	                closed_right_eye: {
	                	type: "f",
	                	value: 0.9
	                },
	                bending: {
	                	type: "f",
	                	value: 0.025
	                },
	                bending_x: {
	                	type: "f",
	                	value: 0
	                },
	                look_azimuth: {
	                	type: "f",
	                	value: 0
	                },
	                look_elevation: {
	                	type: "f",
	                	value: 0
	                },
	                funkyness: {
	                	type: "f",
	                	value: parameters.funkyness
	                },
	                camera_distance: {
	                	type: "f",
	                	value: parameters.camera_distance
	                },
	                backoff: {
	                	type: "f",
	                	value: 0
	                }
	        },
	        vertexShader: [

	                "varying vec2 vUv;",

	                "void main() {",

	                "vUv = vec2( uv.x, uv.y );",
	                "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

	                "}"

	        ].join("\n"),
	        fragmentShader: [
"uniform float time;",
"uniform float iGlobalTime;",
"uniform vec2 iResolution;",
"varying vec2 vUv;",
"",
"",
"////////",
"// paste shadertoy here, begin",
"",
"",
"uniform float closed_left_eye;",
"uniform float closed_right_eye;",
"const float bending = 0.025;",
"const float bending_x = 0.;",
"uniform float look_azimuth;",
"uniform float look_elevation;",
"const float N_birds = 7.;",
"const float Bird_radius = 0.8;",
"uniform float camera_distance;",
"uniform float funkyness;",
"const float steplessiter = 20.;",
"uniform float backoff;",
"    //look_elevation = clamp(look_elevation,-.1,.3);",
"    //look_azimuth = clamp(look_azimuth,-.4,.4);",
"    ",
"#define BACKOFF",
"",
"// as allways, higher is better",
maxitertxt,
"",
"// define one of these",
"//#define CLEAN // at least 10 iterations",
"//#define EVIL_BIRD_IN_THE_DARK // at least 16 iterations",
"#define FUNKY_BACKGROUND",
"",
"// this is cool with FUNKY_BACKGROUND",
"//#define ONLY_BEAK",
"",
"// woho!",
"//#define DANCE_GROOVE",
"//#define DANCE_FUNK",
"",
"//#define EAT_MUSHROOMS",
"",
"//#define UNDERCOVER",
"",
"//#define BANDANA",
"",
"//#define BACKGROUNDTEXTURE",
"",
"const float eps = 0.01;",
"const float neck = 0.48;",
"const float pi = 3.14159;",
"const float pi2 = 6.28319;",
"",
"// raymarching CSG: min = union, max = intersection",
"float sphere(vec3 p, vec3 c, float r)",
"{",
"    return length(p-c) - r;",
"}",
"",
"float plane(vec3 p, vec3 n, float d)",
"{",
"    return dot(p,n)-d;",
"}",
"",
"vec3 bendBody(vec3 p)",
"{",
"    // offset position to compute distance from to give the effect of the object moving",
"    //float bending = 0.015*sin(4.*iGlobalTime);",
"    p.z -= p.y*p.y*bending;",
"    float bend_x = p.y*p.y*bending_x;",
"    p.x -= bend_x;",
"    p.y -= abs(bend_x);",
"    ",
"    #ifdef EAT_MUSHROOMS",
"    p.x = p.x - sin(p.y);",
"    #endif",
"    ",
"    #ifdef DANCE_GROOVE",
"    float o = p.y*p.y*bending*2.*sin(4.*iGlobalTime);",
"    p.x += o;",
"    p.y += abs(o);",
"    #endif",
"    #ifdef DANCE_FUNK",
"    float o2 = p.y*p.y*bending*2.*sin(4.*iGlobalTime);",
"    p.x += o2;",
"    p.y -= abs(o2);",
"    #endif",
"    return p;",
"}",
"",
"float birdieBody(in vec3 p)",
"{",
"    // Model the body as a cylinder with varying radius",
"    float y = clamp(p.y,0.,1.);",
"",
"    float r1 = mix(1.4,0.15,y/neck);",
"    float t = 1. - (y-neck)/(1.-neck);",
"    float r2 = -.85*t*t*t*t + 1.;",
"    r2 *= sqrt(2.*t-t*t);",
"    float r = y<neck ? r1 : r2;",
"    ",
"    float body = length(p.xz) - r*0.1;",
"    return max(max(p.y-1.,-p.y),body);",
"}",
"",
"float birdieBeak1(in vec3 p)",
"{",
"    float d_back = p.z - (-0.02);",
"    float d_bottom = -(p.y - 0.57);",
"    float d_left = sphere(p,vec3(-.15, 0.6, 0.02),.2);",
"    float d_right = sphere(p,vec3(.15, 0.6, 0.02),.2);",
"    ",
"    return max(max(d_left,d_right),max(d_bottom,d_back));",
"}",
"",
"float birdieBeak2(in vec3 p,float openjaw)",
"{",
"    float d_back = p.z - (-0.02);",
"    float d_top = plane(p, vec3(0.,1.,-.6-.3*openjaw), 0.6+.03*openjaw);",
"    float d_left = sphere(p,vec3(-.115, 0.65, 0.06),.2);",
"    float d_right = sphere(p,vec3(.115, 0.65, 0.06),.2);",
"    ",
"    return max(max(d_left,d_right),max(d_top,d_back));",
"}",
"",
"float birdieBeak(in vec3 p)",
"{",
"    float beak1 = birdieBeak1(p);",
"    float beak2 = birdieBeak2(p, 0.);",
"    ",
"    return min(beak1,beak2);",
"}",
"",
"float birdieEyePupil(in vec3 p)",
"{",
"    vec3 off1 = vec3( 0.04, 0.717+0.04*look_elevation, -0.048);",
"    vec3 off2 = vec3( -0.04, 0.717+0.04*look_elevation, -0.048);",
"",
"    float ca = cos(look_azimuth);",
"    float sa = sin(look_azimuth);",
"    ",
"    off1 = vec3(off1.z*sa + off1.x*ca, off1.y, off1.z*ca - off1.x*sa);",
"    off2 = vec3(off2.z*sa + off2.x*ca, off2.y, off2.z*ca - off2.x*sa);",
"    ",
"    return min(length(p-off1),length(p-off2)) - .025; // distance to sphere",
"}",
"",
"float birdieEyeWhite(float body,in vec3 p)",
"{",
"    float d_bottom = plane(p,vec3(0.,-1.,0.),-0.69);",
"    float d_top = plane(p,vec3(0.,1.,0.),0.9);",
"    float d_sphere = min(sphere(p,vec3(0.1,0.75,-0.1),.1),",
"                         sphere(p,vec3(-0.1,0.75,-0.1),.1));",
"    return max(max(body,d_sphere),max(d_top,d_bottom));",
"}",
"",
"float birdieBandana(float body,in vec3 p)",
"{",
"#ifdef BANDANA",
"    float d_bottom = plane(p,vec3(0.,-1.,0.),-0.85);",
"    float d_top = plane(p,vec3(0.,1.,0.),0.91);",
"#else",
"    float d_bottom = plane(p,vec3(0.,-1.,0.),-0.92);",
"    float d_top = plane(p,vec3(0.,1.,0.),0.91);",
"#endif",
"#ifdef UNDERCOVER",
"    return body;",
"#else",
"    return max(body,max(d_top,d_bottom));",
"#endif",
"}",
"",
"float birdieEyeLid(in vec3 p, float closed_left, float closed_right)",
"{",
"    p.y = (p.y-0.75)*0.5 + 0.75;",
"    float d_bottom = plane(p,vec3(-.8*(1.-closed_left),-1.,0.),-0.9 + 0.21*closed_left);",
"    float d_sphere1 = sphere(p,vec3(-0.1,0.75,-0.1),.1);",
"    float d_sphere2 = sphere(p,vec3(0,0.77,0),.1);",
"    float lid1 = max(max(d_sphere1,d_sphere2),d_bottom);",
"",
"    d_bottom = plane(p,vec3(0.8*(1.-closed_right),-1.,0.),-0.9 + 0.21*closed_right);",
"    d_sphere1 = sphere(p,vec3(0.1,0.75,-0.1),.1);",
"    d_sphere2 = sphere(p,vec3(0,0.77,0),.1);",
"    float lid2 = max(max(d_sphere1,d_sphere2),d_bottom);",
"    return min(lid1,lid2);",
"}",
"",
"vec4 birdie(in vec3 p)",
"{",
"    p.y += 0.5;",
"    p = bendBody(p);",
"    float body = birdieBody(p);",
"    float beak = birdieBeak(p);",
"    float eyepupil = max(body,birdieEyePupil(p));",
"    float eyewhite = birdieEyeWhite(body,p);",
"    float eyelid = birdieEyeLid(p,closed_left_eye, closed_right_eye);",
"    float ninjabandana = birdieBandana(body,p);",
"    ",
"    #ifdef ONLY_BEAK",
"    body += 10.;",
"    eyepupil += 10.;",
"    eyewhite += 10.;",
"    eyelid += 10.;",
"    #endif",
"",
"    float m = min(min(min(body,beak),min(eyepupil,eyewhite)),eyelid);",
"    vec4 r;",
"    if (m==beak) return vec4(0.8, 0.4, 0.2, m);",
"    if (m==eyepupil) return vec4(0.0, 0.0, 0.0, m);",
"    if (m==ninjabandana) return vec4(0.1, 0.2, 0.3, m);",
"    if (m==eyewhite) return vec4(1.0, 1.0, 1.0, m);",
"    if (m==eyelid) return vec4(0.6, 0.6, 0.6, m);",
"    return vec4(0.8, 0.8, 0.8, m); // m==body",
"}",
"",
"vec4 scene(in vec3 p)",
"{",
"    vec4 br = vec4(0.,0.,0.,10000.);",
"    float a = floor(mod(atan(p.x,p.z)+pi2*(N_birds+0.5)/N_birds,pi2)/pi2*N_birds);",
"    float ang = pi2*a/N_birds;",
"    float ca = cos(ang);",
"    float sa = sin(ang);",
"",
"    vec3 q = p - vec3(sa*Bird_radius,0,ca*Bird_radius);",
"    q = vec3(q.z*sa - q.x*ca, q.y, q.z*ca + q.x*sa);",
"",
"    vec4 b = birdie(q);",
"    if (b.w < br.w)",
"        br = b;",
"    ",
"    return br;",
"}",
"",
"// gradient normal",
"vec3 getNormal(in vec3 p,float w)",
"{",
"    vec3 normal;",
"    vec3 ep = vec3(eps,0,0);",
"    normal.x = scene(p + ep.xyz).w - w;",
"    normal.y = scene(p + ep.yxz).w - w;",
"    normal.z = scene(p + ep.yzx).w - w;",
"    return normalize(normal);",
"}",
"",
"void mainImage( out vec4 fragColor, in vec2 fragCoord )",
"{",
"	vec2 uv = (fragCoord.xy - iResolution.xy*0.5) / iResolution.yy;    ",
"    ",
"    vec3 rayStart = vec3(0,0,camera_distance);",
"    vec3 rayDir = normalize(vec3(uv,-1));",
"    ",
"    float ca,sa;",
"    float rotatex = -0.05+0.1*sin(.1*iGlobalTime);",
"    float rotatey = .2*iGlobalTime;",
"    float steps = steplessiter;",
"    float funkval = funkyness;",
"    ",
"    #ifdef BACKOFF",
"    float backoff_v = clamp(backoff,0.,1.);",
"    rotatex = -(backoff_v*backoff_v*2.9143 - 3.4143*backoff_v)*3.14/2.;",
"    rotatey += 2.*(1.+backoff*backoff);",
"    rayStart.xz *= (1.-backoff_v)*(1.-backoff_v);",
"    steps = mix(steplessiter,2.0,backoff_v);",
"    funkval = pow(backoff_v,21.)*10.;",
"    #endif",
"    ",
"    //a = 3.14+.4*iGlobalTime;",
"    ca = cos(rotatex);",
"    sa = sin(rotatex);",
"	rayStart = vec3(rayStart.x, rayStart.z*sa + rayStart.y*ca, rayStart.z*ca - rayStart.y*sa);",
"    rayDir = vec3(rayDir.x, rayDir.z*sa + rayDir.y*ca, rayDir.z*ca - rayDir.y*sa);",
"",
"    #ifdef BACKOFF",
"    rayStart.z += 3.*max(0.,backoff-1.);",
"    #endif",
"    //float a = 3.e4+1.4*iGlobalTime;",
"    ca = cos(rotatey);",
"    sa = sin(rotatey);",
"    rayStart = vec3(rayStart.z*sa + rayStart.x*ca, rayStart.y, rayStart.z*ca - rayStart.x*sa);",
"    rayDir = vec3(rayDir.z*sa + rayDir.x*ca, rayDir.y, rayDir.z*ca - rayDir.x*sa);",
"",
"    #ifdef BACKOFF",
"    rayStart.y += backoff_v*3.;",
"    #endif",
"    ",
"    vec3 p;",
"    float t = 0.0;",
"    vec4 currentColor;",
"    for (int i=0; i<RM_MAX_ITER; ++i)",
"    {",
"        float k = min(1.,steps);",
"        steps -= k;",
"        p = rayStart + rayDir*t;",
"        currentColor = scene(p);",
"        t += currentColor.w*k;",
"        if (currentColor.w*k<eps) break;",
"    }",
"",
"    vec3 finalColor = vec3(0,0,0);",
"    vec3 normal = getNormal(p,currentColor.w);",
"    //vec3 normal = vec3(0,0,1);",
"    vec3 light1 = vec3(sin(iGlobalTime),cos(iGlobalTime),0);",
"    vec3 light2 = vec3(0,0,-1);",
"    //            finalColor = normal;",
"    //            finalColor = vec3(1,0,1) *",
"    //                dot(vec3(1.,sin(iGlobalTime ),cos(iGlobalTime )),normal);",
"    float diffuse1 = 0.1+dot(light1,normal);",
"    float diffuse2 = 0.1+dot(light2,normal);",
"    float specular = pow(max(0.,dot(light1,normal)),21.);",
"    ",
"//    #ifdef CLEAN",
"    if (currentColor.w>funkval)",
"    //if (currentColor.w>eps)",
"    {",
"        currentColor = vec4(0.,0.,0.,currentColor.w);",
"    }",
"//    #endif",
"    ",
"    #ifdef EVIL_BIRD_IN_THE_DARK",
"    if (currentColor.w>0.)",
"    {",
"        currentColor = vec4(0.,0.,0.,currentColor.w);",
"    }",
"    #endif",
"",
"",
"    //float specular = 0.;",
"    float ambient = 0.2;",
"    finalColor = currentColor.xyz *",
"        (ambient + max(0.,0.5* diffuse1) + 0.5*diffuse2 + specular);",
"    ",
"	fragColor = vec4(finalColor, min(1.,max(0.,1.-currentColor.w) + length(finalColor)));",
"",
"    #ifdef BACKGROUNDTEXTURE",
"    fragColor = mix(vec4(pow(texture2D (iChannel0,fragCoord/iResolution.xy).r,21.)), fragColor, fragColor.a);",
"    #endif",
"}",
"",
"",
"",
"",
"// paste shadertoy here, stop",
"////////",
"",
"void main()",
"{",
"	vec4 fragColor;",
"	vec2 fragCoord = vUv.xy*iResolution;",
"",
"	mainImage(fragColor,fragCoord);",
"    ",
"	gl_FragColor = fragColor;",
"}",
""].join("\n"),
			depthTest: false,
			depthWrite: false,
			blending: THREE.NormalBlending,
			transparent: true
	    });

		//quad = new THREE.Mesh(quadgeometry, this.quadmaterial, this.compositeShader);
		quad = new THREE.Mesh(quadgeometry, this.quadmaterial);
    	scene.add(quad);

		camera = new THREE.OrthographicCamera(window.innerWidth / -2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / -2, -100, 100);
	};

	this.start = function ( t, parameters ) {

	};

	this.end = function ( ) {
		
	};	

	this.update = function ( t, perc, gt ) {		
	    quad.material.uniforms['iGlobalTime'].value = gt;
	    switch(this.parameters.input.backoff)
	    {
	    	case 0: quad.material.uniforms['backoff'].value = 0; break;
	    	case 1: quad.material.uniforms['backoff'].value = 1-Math.cos(Math.min(Math.PI,0.3*t)); break;
	    	case 2: quad.material.uniforms['backoff'].value = 2; break;
	    }
	    //quad.material.uniforms['funkyness'].value = 100+Math.sin(t)*100;

		if ( this.renderToTexture )
			renderer.render( scene, camera, this.fbo, this.clearBuffer );
		else
			renderer.render( scene, camera );
	};

};