#version 330
precision highp float;

uniform float TrackTime;
uniform mat4 mvprMatrix;

in vec4 vVertex;

out vec4 varColor;

vec4 HSVAtoRGBA(vec4 HSVA);
float rand(vec2 co);
float mysinStep(float T1, float T2, float V1, float V2, float curT);

vec4 functionPosition(float curTime, vec4 myVertex, bool clamper);
vec4 cubePosition(float curTime, vec4 syncTimes, vec4 myVertex);
vec4 spherePosition(float curTime, vec4 myVertex);
float calcNewPosition(float curTime, vec4 syncTimes, vec2 Seed);

void main()
{
	vec4 times = vec4(7730.1, 1921.693, 240.212,34633.802); //Aufteilung: Offset, Dauer eines Zyklus, Dauer eines Klanges (1/8 eines Zyklus, 4 Töne pro Zyklus), Start des Übergangs zur nächsten Scene
	vec4 HighValue = vec4(0.0);
	float HighX = 0.0;
	if(TrackTime-times.x < 3.0*times.y)
		HighValue = functionPosition(TrackTime, vVertex, false);
	if(TrackTime-times.x >= 3.0*times.y && TrackTime-times.x < 4.0*times.y) {
		vec4 withoutClamp = functionPosition(TrackTime, vVertex, false);
		vec4 withClamp = functionPosition(TrackTime, vVertex, true);

		HighValue.w = withoutClamp.w;
		HighValue.x = mysinStep(0.0, times.y, withoutClamp.x, withClamp.x, TrackTime-times.x-3.0*times.y);
		HighValue.y = mysinStep(0.0, times.y, withoutClamp.y, withClamp.y, TrackTime-times.x-3.0*times.y);
		HighValue.z = mysinStep(0.0, times.y, withoutClamp.z, withClamp.z, TrackTime-times.x-3.0*times.y);
	}
	if(TrackTime-times.x >= 4.0*times.y && TrackTime-times.x < 6.0*times.y)
		HighValue = functionPosition(TrackTime, vVertex, true);

	if(TrackTime-times.x >= 6.0*times.y && TrackTime-times.x < 7.0*times.y) {
		vec4 withClamp = functionPosition(TrackTime, vVertex, true);
		vec4 cubePosition = cubePosition(TrackTime, times, vVertex);

		HighValue.w = withClamp.w;
		HighValue.x = mysinStep(0.0, times.y, withClamp.x, cubePosition.x, TrackTime-times.x-6.0*times.y);
		HighValue.y = mysinStep(0.0, times.y, withClamp.y, cubePosition.y, TrackTime-times.x-6.0*times.y);
		HighValue.z = mysinStep(0.0, times.y, withClamp.z, cubePosition.z, TrackTime-times.x-6.0*times.y);
	}
	if(TrackTime-times.x >= 7.0*times.y && TrackTime-times.x < 10.0*times.y)
		HighValue = cubePosition(TrackTime, times, vVertex);

	if(TrackTime-times.x >= 10.0*times.y && TrackTime-times.x < 11.0*times.y) {
		vec4 lastCubePosition = cubePosition(TrackTime, times, vVertex);
		vec4 firstSpherePosition = spherePosition(TrackTime, vVertex);

		HighValue.w = vVertex.w;
		HighValue.x = mysinStep(0.0, times.y, lastCubePosition.x, firstSpherePosition.x, TrackTime-times.x-10.0*times.y);
		HighValue.y = mysinStep(0.0, times.y, lastCubePosition.y, firstSpherePosition.y, TrackTime-times.x-10.0*times.y);
		HighValue.z = mysinStep(0.0, times.y, lastCubePosition.z, firstSpherePosition.z, TrackTime-times.x-10.0*times.y);
	}
	if(TrackTime-times.x >= 11.0*times.y) {
		HighValue = spherePosition(TrackTime, vVertex);		
	}
	if(TrackTime > times.w) {
		//Zusammenziehen + explodieren
		float scaleVal = calcNewPosition(TrackTime, times, vVertex.xy*vec2(1.123));
		HighValue.xyz *= vec3(scaleVal);
		
		HighX = HighValue.z*(0.5)+0.5;
		HighX /= scaleVal;//Keep the H between [0,1]
	}
	else
		HighX = HighValue.z*(0.5)+0.5;
		

	float myEffectStartTime = TrackTime-times.x;
	
	float effect1 = 1.0;
	effect1 = mod(myEffectStartTime/times.y, 1.0);

	
	float effect2 = mod(myEffectStartTime/times.z, 1.0);

	float eff2Rand = step(0.95, rand(vVertex.xy*vec2((myEffectStartTime-mod(myEffectStartTime, times.z))/100.0)));

	float eff2Times = mod(myEffectStartTime, times.y)/times.z;

	vec2 eff3Coords = vec2(vVertex.xy*vec2(0.5)+vec2(0.5));//-1bis1 -> 0bis1; Für Kreuz aus blinkenden Partikeln 0.5/128.0 die ersten, in 1.0/128.0er-Schritten weiter
	float rand1 = rand(vec2((myEffectStartTime-mod(myEffectStartTime, times.z))*0.1));
	rand1 -= mod(rand1, 1.0/128.0);
	rand1 += 0.5/128;
	float rand2 = rand(vec2((myEffectStartTime-mod(myEffectStartTime, 240.21))*0.1+0.1));
	rand2 -= mod(rand2, 1.0/128.0);
	rand2 += 0.5/128;
	
	float H = 0.0;
	if((eff3Coords.x == rand1 || eff3Coords.y == rand1 || eff3Coords.x == rand2 || eff3Coords.y == rand2 || eff2Rand == 1.0) && eff2Times < 4.0) {
		effect2 *= 4.0;
		H = 3.0/6.0+HighX*1.0/6.0;
	}
	else {
		effect2 = 1.0;
		H = HighX*(1.0/6.0);
	}
	float effect3 = 1.0;
	if(TrackTime > times.w+times.y)
		effect3 = mysinStep(times.w+times.y, times.w+2.0*times.y, 1.0,0.0, TrackTime);

	varColor = HSVAtoRGBA(vec4(H, 0.8,effect3*0.6,effect1*effect2*effect3*0.8+0.1));

	gl_Position = mvprMatrix*HighValue;
}
vec4 functionPosition(float curTime, vec4 myVertex, bool clamper){
	float pi = 3.1415926535;
	vec4 returner = myVertex;
	float curRand = rand(myVertex.xy)*0.1;
	returner.x = sin(curTime/300.0-myVertex.y*2.0*pi);
	returner.y = cos(curTime/300.0-myVertex.y*2.0*pi);
	returner.z = sin((curTime/300.0-myVertex.y*pi))*1.0;
	if(clamper) {
		vec3 randomV = vec3(rand(vVertex.yx), rand(vVertex.xy), rand(vVertex.xz))*vec3(0.2);
		returner.xyz += randomV;
		returner.xyz = clamp(returner.xyz, -0.7,0.7);
	}
	else {
		vec3 randomV = vec3(rand(vVertex.yx), rand(vVertex.xy), rand(vVertex.xy))*vec3(0.1);
		//vec3 randomV = vec3(rand(vVertex.yx), rand(returner.xy), rand(returner.xz))*vec3(0.2);//This also gives interesting results!
		returner.xyz += randomV;
		}
	return returner;
}
vec4 cubePosition(float curTime, vec4 syncTimes, vec4 myVertex) {
	vec4 returner = vec4(myVertex.x, myVertex.y, 0.0, myVertex.w);
	returner.z = sin((rand(myVertex.xy))*clamp((curTime-syncTimes.x)/syncTimes.y, 0.0,1.0)*(curTime/1000.0));
	return returner;
}
vec4 spherePosition(float curTime, vec4 myVertex) {
	vec4 returner = vec4(myVertex.x, myVertex.y, 0.0, myVertex.w);
	returner.xy = vec2(rand(myVertex.xy*vec2(0.1))*sin(curTime/1000.0*rand(myVertex.yx)), rand(myVertex.yx*vec2(0.1))*sin(curTime/1000.0*rand(myVertex.xy)));
	returner.xy = returner.xy*vec2(2.0);

	returner.z = sqrt(1.0-(returner.x*returner.x+returner.y*returner.y))*(step(0.5,rand(myVertex.yx*vec2(0.5)))*2.0-1.0);
	return returner;
}
float calcNewPosition(float curTime, vec4 syncTimes, vec2 Seed) {
	float thisRand = rand(Seed)*0.25;
	float effectTime = curTime-syncTimes.w;
	float returner = 1.0;
	if(effectTime < syncTimes.y) {
		returner = mysinStep(syncTimes.w, syncTimes.w+syncTimes.y, 1.0, 0.5, effectTime)+thisRand;
	}
	else {
		returner = mysinStep(syncTimes.w+syncTimes.y, syncTimes.w+syncTimes.y*2.0, 0.5, 7.0, effectTime);
		returner = returner+returner*thisRand;
	}
	return returner;
}

float mysinStep(float T1, float T2, float V1, float V2, float curT) {
	float PI = 3.1415926535;
	float curSin = 0.5*sin(PI*(((curT-T1)/(T2-T1))-0.5))+0.5;
	float curV = curSin*(V2-V1)+V1;
	return curV;
}

vec4 HSVAtoRGBA(vec4 HSVA)
{
	vec4 RGBAreturner;
	RGBAreturner.a = HSVA.w;
	HSVA.x *= 360.0;
	int hi = int((HSVA.x-mod(HSVA.x, 60.0))/60.0);
	float f = HSVA.x/60.0-hi;
	float p = HSVA.z*(1-HSVA.y);
	float q = HSVA.z*(1-HSVA.y*f);
	float t = HSVA.z*(1-HSVA.y*(1-f));
	
	switch(hi) {
	case 0:
	case 6:
		RGBAreturner.rgb = vec3(HSVA.z, t, p);
		break;
	case 1:
		RGBAreturner.rgb = vec3(q, HSVA.z, p);
		break;
	case 2:
		RGBAreturner.rgb = vec3(p, HSVA.z, t);
		break;
	case 3:
		RGBAreturner.rgb = vec3(p, q, HSVA.z);
		break;
	case 4:
		RGBAreturner.rgb = vec3(t, p, HSVA.z);
		break;
	case 5:
		RGBAreturner.rgb = vec3(HSVA.z, p, q);
		break;
	default:
		RGBAreturner.rgb = vec3(0.0);
		break;
	}
	return RGBAreturner;
}

float rand(vec2 co)
{
	return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}