scene.org File Archive

File download

<root>­/­parties­/­2025­/­sessions25­/­code_graphics/sessions-shader.txt

File size:
32 920 bytes (32.15K)
File date:
2025-12-16 16:39:04
Download count:
all-time: 0

Preview

precision highp float;
uniform float time;
uniform vec2 resolution;
out vec4 fragColor;

#define Rot(a) mat2(cos(a),-sin(a),sin(a),cos(a))
#define antialiasing(n) n/min(resolution.y,resolution.x)
#define S(d) 1.-smoothstep(-1.2,1.2, (d)*resolution.y )
#define B(p,s) max(abs(p).x-s.x,abs(p).y-s.y)
#define deg45 .707
#define R45(p) (( p + vec2(p.y,-p.x) ) *deg45)
#define Tri(p,s) max(R45(p).x,max(R45(p).y,B(p,s)))
#define PUV(p) vec2(log(length(p)),atan(p.y/p.x))
#define SkewX(a) mat2(1.0,tan(a),0.0,1.0)
#define SkewY(a) mat2(1.0,0.0,tan(a),1.0)
#define PI 3.14159
#define mapSizeX 17.
#define mapSizeY 20.
#define FONT_H 0.06
#define FONT_THICK 0.02

vec3 pathData[8] = vec3[](
    vec3(mapSizeX*0.4, 0.0, -mapSizeY*0.6),
    vec3(-mapSizeX*0.3, 0.0, -mapSizeY*0.7),
    vec3(-mapSizeX*0.6, 0.0, -mapSizeY*0.3),
    vec3(-mapSizeX*0.15, 0.0, -mapSizeY*0.05),
    vec3(-mapSizeX*0.35, 0.0, mapSizeY*0.3),
    vec3(-mapSizeX*0.15, 0.0, mapSizeY*0.65),
    vec3(mapSizeX*0.25, 0.0, mapSizeY*0.75),
    vec3(mapSizeX*0.6, 0.0, mapSizeY*0.5)
);

float Hash21(vec2 p) {
    p = fract(p*vec2(234.56,789.34));
    p+=dot(p,p+34.56);
    return fract(p.x+p.y);
}

float noise (vec2 st) {
    vec2 i = floor(st);
    vec2 f = fract(st);

    float a = Hash21(i);
    float b = Hash21(i + vec2(1.0, 0.0));
    float c = Hash21(i + vec2(0.0, 1.0));
    float d = Hash21(i + vec2(1.0, 1.0));

    vec2 u = f*f*(3.0-2.0*f);
    return mix(a, b, u.x) + (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}

float yawBetweenPoints(vec3 a, vec3 b) {
    vec2 d = (b - a).xz; 
    return atan(d.x, d.y);
}

float pitchBetweenPoints(vec3 a, vec3 b) {
    vec3 d = b - a;
    float h = length(d.xz);
    return atan(d.y, h); 
}

float lerpAngle(float a, float b, float t) {
    vec2 ca = vec2(sin(a), cos(a));
    vec2 cb = vec2(sin(b), cos(b));
    vec2 c = mix(ca, cb, t);
    if(length(c) < 1e-6) return a;
    c = normalize(c);
    return atan(c.x, c.y);
}

mat3 rotX3(float a) {
    float c = cos(a), s = sin(a);
    return mat3(1.0, 0.0, 0.0,
                0.0,  c,  s,
                0.0, -s,  c);
}

mat3 rotY3(float a) {
    float c = cos(a), s = sin(a);
    return mat3(c, 0.0, -s,
                0.0,1.0, 0.0,
                s, 0.0,  c);
}

mat3 rotZ3(float a) {
    float c = cos(a);
    float s = sin(a);
    return mat3(
        c, -s, 0.0,
        s,  c, 0.0,
        0.0, 0.0, 1.0
    );
}

// thx, iq! https://iquilezles.org/articles/distfunctions2d/
float sdPolygon(vec2[4] v, in vec2 p )
{
    float d = dot(p-v[0],p-v[0]);
    float s = 1.0;
    for( int i=0, j=4-1; i<4; j=i, i++ )
    {
        vec2 e = v[j] - v[i];
        vec2 w =    p - v[i];
        vec2 b = w - e*clamp( dot(w,e)/dot(e,e), 0.0, 1.0 );
        d = min( d, dot(b,b) );
        bvec3 c = bvec3(p.y>=v[i].y,p.y<v[j].y,e.x*w.y>e.y*w.x);
        if( all(c) || all(not(c)) ) s*=-1.0;  
    }
    return s*sqrt(d);
}

// thx, iq! https://iquilezles.org/articles/distfunctions2d/
float sdHexagon( in vec2 p, in float r )
{
    const vec3 k = vec3(-0.866025404,0.5,0.577350269);
    p = abs(p);
    p -= 2.0*min(dot(k.xy,p),0.0)*k.xy;
    p -= vec2(clamp(p.x, -k.z*r, k.z*r), r);
    return length(p)*sign(p.y);
}

//thx Shane! getting the hex uv logic from the Shane's implementation here: https://www.shadertoy.com/view/Xljczw
const vec2 s = vec2(1.7320508, 1);
vec4 getHex(vec2 p){
    vec4 hC = floor(vec4(p, p - vec2(1, .5))/s.xyxy) + .5;
    vec4 h = vec4(p - hC.xy*s, p - (hC.zw + .5)*s);
    return dot(h.xy, h.xy)<dot(h.zw, h.zw) ? vec4(h.xy, hC.xy) : vec4(h.zw, hC.zw + .5);
}

float lineTo(vec2 p, vec2 a, vec2 b){
    float k = dot(p-a,b-a)/dot(b-a,b-a);
    vec2 distanceToPoint = mix(a,b,clamp(k,0.,1.));
    return distance(p,distanceToPoint);
}

vec2 getSphereMap(vec2 p, float size){
    p*=size;
    float r = dot(p, p);
    float z = sqrt(1.0 - r);
    vec3 q = vec3(p, z);
    //q.xz*=Rot(radians(53.+20.*time*0.5));
    vec3 normal = normalize(q);

    float longitude = atan(normal.x, normal.z);
    float latitude  = asin(normal.y);

    float u = longitude / (2. * PI) + 0.5;
    float v = latitude / (2.*PI) + 0.5;

    p = vec2(u,v);
    p -= 0.5;
    p*=size;
    return p;
}

float cA(vec2 p){
    p.x = abs(p.x);
    float h = FONT_H;
    float d = lineTo(p,vec2(0.,h),vec2(h,-h))-FONT_THICK;
    return d;
}

float cF(vec2 p){
    float h = FONT_H;
    float d = lineTo(p,vec2(-h,h),vec2(-h,-h))-FONT_THICK;
    float d2 = lineTo(p,vec2(-h,h),vec2(h,h))-FONT_THICK;
    d = min(d,d2);
    d2 = lineTo(p,vec2(-h*0.25,0.),vec2(h,0.))-FONT_THICK;
    d = min(d,d2);
    return d;
}

float cG(vec2 p){
    vec2 prevP = p;
    float h = FONT_H;
    float d = lineTo(p,vec2(-h,h),vec2(-h,-h))-FONT_THICK;
    p.y = abs(p.y);
    float d2 = lineTo(p,vec2(-h,h),vec2(h,h))-FONT_THICK;
    d = min(d,d2);
    p = prevP;
    d2 = lineTo(p,vec2(-h*0.25,0.),vec2(h,0.))-FONT_THICK;
    d = min(d,d2);
    d2 = lineTo(p,vec2(h,0.),vec2(h,-h))-FONT_THICK;
    d = min(d,d2);
    return d;
}

float cI(vec2 p){
    vec2 prevP = p;
    float h = FONT_H;
    float d = lineTo(p,vec2(0.,h),vec2(0.,-h))-FONT_THICK;
    return d;
}

float cL(vec2 p){
    vec2 prevP = p;
    float h = FONT_H;
    float d = lineTo(p,vec2(-h,h),vec2(-h,-h))-FONT_THICK;
    float d2 = lineTo(p,vec2(-h,-h),vec2(h,-h))-FONT_THICK;
    d = min(d,d2);
    return d;
}

float cN(vec2 p){
    vec2 prevP = p;
    float h = FONT_H;
    p.x = abs(p.x);
    float d = lineTo(p,vec2(h,h),vec2(h,-h))-FONT_THICK;
    p = prevP;
    float d2 = lineTo(p,vec2(h,h),vec2(-h,h))-FONT_THICK;
    d = min(d,d2);
    return d;
}

float cO(vec2 p){
    vec2 prevP = p;
    float h = FONT_H;
    p.x = abs(p.x);
    float d = lineTo(p,vec2(h,h),vec2(h,-h))-FONT_THICK;
    p = prevP;
    p.y = abs(p.y);
    float d2 = lineTo(p,vec2(h,h),vec2(-h,h))-FONT_THICK;
    d = min(d,d2);
    return d;
}

float cP(vec2 p){
    float h = FONT_H;
    float d = lineTo(p,vec2(-h,0.0),vec2(-h,-h))-FONT_THICK;
    float d2 = lineTo(p,vec2(-h,h),vec2(h,h))-FONT_THICK;
    d = min(d,d2);
    d2 = lineTo(p,vec2(-h,0.),vec2(h,0.))-FONT_THICK;
    d = min(d,d2);
    d2 = lineTo(p,vec2(h,h),vec2(h,0.))-FONT_THICK;
    d = min(d,d2);
    return d;
}

float c2(vec2 p){
    vec2 prevP = p;
    float h = FONT_H;
    p.y = abs(p.y);
    float d = lineTo(p,vec2(h,h),vec2(-h,h))-FONT_THICK;
    p = prevP;
    float d2 = lineTo(p,vec2(h,0.),vec2(-h,0.))-FONT_THICK;
    d = min(d,d2);
    d2 = lineTo(p,vec2(h,h),vec2(h,0.))-FONT_THICK;
    d = min(d,d2);
    d2 = lineTo(p,vec2(-h,0.),vec2(-h,-h))-FONT_THICK;
    d = min(d,d2);
    return d;
}

float c3(vec2 p){
    vec2 prevP = p;
    float h = FONT_H;
    p.y = abs(p.y);
    float d = lineTo(p,vec2(h,h),vec2(-h,h))-FONT_THICK;
    p = prevP;
    float d2 = lineTo(p,vec2(h*0.25,0.),vec2(-h,0.))-FONT_THICK;
    d = min(d,d2);
    d2 = lineTo(p,vec2(h,h),vec2(h,-h))-FONT_THICK;
    d = min(d,d2);
    return d;
}

float c4(vec2 p){
    float h = FONT_H;
    float d = lineTo(p,vec2(-h,h),vec2(-h,0.0))-FONT_THICK;
    float d2 = lineTo(p,vec2(h,0.0),vec2(-h,0.0))-FONT_THICK;
    d = min(d,d2);
    d2 = lineTo(p,vec2(h,0.0),vec2(h,-h))-FONT_THICK;
    d = min(d,d2);
    d2 = lineTo(p,vec2(h,h),vec2(h,h*0.75))-FONT_THICK;
    d = min(d,d2);
    return d;
}

float c5(vec2 p){
    vec2 prevP = p;
    p.y*=-1.;
    float d = c2(p);
    return d;
}

float c6(vec2 p){
    vec2 prevP = p;
    p.y*=-1.;
    float d = cP(p);
    return d;
}

float c7(vec2 p){
    vec2 prevP = p;
    p*=-1.;
    float d = cL(p);
    return d;
}

float c8(vec2 p){
    vec2 prevP = p;
    float h = FONT_H;
    float d = cO(p);
    float d2 = lineTo(p,vec2(-h,0.),vec2(h,0.0))-FONT_THICK;
    d = min(d,d2);
    return d;
}

float c9(vec2 p){
    vec2 prevP = p;
    p.x*=-1.;
    float d = cP(p);
    return d;
}

float drawNumbers(vec2 p, int char){
    float d = 10.;
    if(char == 0) {
        d = cO(p);
    } else if(char == 1){
        d = cI(p);
    } else if(char == 2){
        d = c2(p);
    } else if(char == 3){
        d = c3(p);
    } else if(char == 4){
        d = c4(p);
    } else if(char == 5){
        d = c5(p);
    } else if(char == 6){
        d = c6(p);
    } else if(char == 7){
        d = c7(p);
    } else if(char == 8){
        d = c8(p);
    } else if(char == 9){
        d = c9(p);
    }
    
    return d;
}

float go(vec2 p){
    float s = FONT_H+0.03;
    float d = cG(p-vec2(-s,0.0));
    float d2 = cO(p-vec2(s,0.0));
    d = min(d,d2);
    return d;
}

float c25(vec2 p){
    float s = FONT_H+0.03;
    float d = c2(p-vec2(-s,0.0));
    float d2 = c5(p-vec2(s,0.0));
    d = min(d,d2);
    return d;
}

float animNumbers(vec2 p, float n){
    float s = FONT_H+0.03;
    float d = drawNumbers(p-vec2(-s,0.0),int(mod(time*7.+n,10.)));
    float d2 = drawNumbers(p-vec2(s,0.0),int(mod(time*10.+n,10.)));
    d = min(d,d2);
    return d;
}

float finallap(vec2 p){
    p*=1.5;
    float s = FONT_H+0.03;
    float d = cF(p-vec2(-s*7.5,0.0));
    float d2 = cI(p-vec2(-s*5.5,0.0));
    d = min(d,d2);
    d2 = cN(p-vec2(-s*3.5,0.0));
    d = min(d,d2);
    d2 = cA(p-vec2(-s*1.5,0.0));
    d = min(d,d2);
    d2 = cL(p-vec2(-s*-0.5,0.0));
    d = min(d,d2);
    d2 = cL(p-vec2(s*3.5,0.0));
    d = min(d,d2);
    d2 = cA(p-vec2(s*5.5,0.0));
    d = min(d,d2);
    d2 = cP(p-vec2(s*7.5,0.0));
    d = min(d,d2);
    return d;
}

float goal(vec2 p){
    float s = FONT_H+0.03;
    float d = cG(p-vec2(-s*3.,0.0));
    float d2 = cO(p-vec2(-s,0.0));
    d = min(d,d2);
    d2 = cA(p-vec2(s,0.0));
    d = min(d,d2);
    d2 = cL(p-vec2(s*3.0,0.0));
    d = min(d,d2);
    return d;
}

float times(vec2 p){
    p*=2.0;
    float s = FONT_H+0.03;
    float d = drawNumbers(p-vec2(-s*3.5,0.0),int(mod(time,10.)));
    float d2 = drawNumbers(p-vec2(-s*1.5,0.0),int(mod(time*5.,10.)));
    d = min(d,d2);
    d2 = drawNumbers(p-vec2(s*1.5,0.0),int(mod(time*10.,10.)));
    d = min(d,d2);
    d2 = drawNumbers(p-vec2(s*3.5,0.0),int(mod(time*20.,10.)));
    d = min(d,d2);
    
    p*=SkewX(radians(-15.));
    p.x+=0.02;
    p.x = abs(p.x)-0.015;
    p.y-=0.07;
    d2 = B(p,vec2(0.01,0.03));
    d = min(d,d2);
    return d;
}

float speedMeter(vec2 p){
    p*=3.0;
    float s = FONT_H+0.03;
    float d = drawNumbers(p-vec2(-s*2.,0.0),3);
    float d2 = drawNumbers(p,int(mod(time*11.,10.)));
    d = min(d,d2);
    d2 = drawNumbers(p-vec2(s*2.,0.0),int(mod(time*16.,10.)));
    d = min(d,d2);
    return d;
}

float power(vec2 p){
    float d = abs(B(p,vec2(0.195,0.02)))-0.005;
    float d2 = p.x-sin(time*0.3)*0.1;
    d2 = max(abs(p.y)-0.008,d2);
    d2 = max(-p.x-0.18,d2);
    d = min(d,d2);
    return d;
}

vec3 startLine(vec2 p, vec3 col, float morph){
    vec2 prevP = p;
    float d = B(p,vec2(1.3,0.28));
    col = mix(col,vec3(0.7),mix(0.,S(d),morph));
    p = mod(p,0.4)-0.2;
    d = B(p,vec2(0.1));
    p = prevP;
    p+=0.2;
    p = mod(p,0.4)-0.2;
    float d2 = B(p,vec2(0.1));
    d = min(d,d2);
    p = prevP;
    d = max(B(p,vec2(1.3,0.28)),d);
    col = mix(col,vec3(0.),mix(0.,S(d),morph));
    return col;
}

float arrow(vec2 p){
    vec2 prevP  = p;
    p.x*=1.5;
    p.y*=-1.;
    p.y-=0.25;
    float d = Tri(p,vec2(0.5));
    p.y+=0.25;
    float d2 = Tri(p,vec2(0.5));
    d = max(-d2,d);
    
    p = prevP;
    p.y-=0.35;
    p.x*=1.5;
    p.y*=-1.;
    p.y-=0.25;
    d2 = Tri(p,vec2(0.5));
    p.y+=0.25;
    float d3 = Tri(p,vec2(0.5));
    d2 = max(-d3,d2);
    d = min(d,d2);
    return d;
}

float arrows(vec2 p){
    p.y-=time*0.1;
    p.y*=-1.;
    p.y = mod(p.y,0.5)-0.25;
    p*=2.;
    float d = arrow(p);
    return d;
}

float arrows2(vec2 p){
    p.y=abs(p.y);
    p.y-=time*0.1;
    p.y = mod(p.y,0.1)-0.05;
    p.x*=2.;
    float d = Tri(p,vec2(0.05));
    return d;
}

float pattern1(vec2 p, float n){
    vec2 prevP = p;
    float d = 10.;
    for(int i = 1; i<3; i++){
        p*=Rot(radians(n*float(i)*30.*time));
        p = abs(p)-float(i)*0.1;
        p*=Rot(radians(n*float(i)*30.));
        float d2 = arrows(p);
        d = min(d,d2);
    }
    return d;
}

float pattern2(vec2 p, float n){
    p*=Rot(radians(45.));
    p.x+=time*(0.5*n);
    p.x = mod(p.x,0.2)-0.1;
    float d = abs(p.x)-0.05;
    return d;
}

float obstacle(vec2 p, vec2 c, float r) {
    vec2 q = p - c;
    vec2 prevQ = q;
    q*=Rot(radians(30.*time*2.));
    float d = abs(length(q) - r)-0.02;
    d = max(-(abs(q.y)-0.05),d);
    q = prevQ;
    float d2 = length(q) - (r*0.8);
    d = min(d,d2);
    q = prevQ;
    q*=Rot(radians(-20.*time*1.8));
    q.x = abs(q.x)-0.1;
    d2 = length(q)-0.02;
    d = max(-d2,d);
    return d;
}

float drawHexBg(vec2 p){
    p.x+=time*0.5;
    vec4 hgr = getHex(p);
    vec4 prevHgr = hgr;
    float n = Hash21(hgr.zw);
    
    float d = 10.;
    
    float dir = 1.;
    if(n<0.5){
        dir = -1.;
    }
    
    float s = 0.07;
    hgr.xy*=Rot(radians(30.*dir));
    hgr.y = abs(hgr.y)-0.55;
    float d2 = abs(length(hgr.xy)-0.275)-s;
    d = min(abs(d)-0.01,d2);
    hgr.y +=0.09;
    hgr.xy*=Rot(radians(30.*time*2.+n));
    d2 = length(hgr.xy)-0.07;
    d2 = abs(d2)-0.015;
    d2 = max(-(abs(hgr.x)-0.02),d2);
    d = min(d,d2);
    hgr= prevHgr;
    hgr.xy*=Rot(radians(60.*-dir));
    d2 = B(hgr.xy,vec2(s,0.6));
    d = min(d,d2);
    hgr.x = abs(hgr.x)-0.15;
    d2 = arrows2(hgr.xy);
    d = min(d,d2);
    
    return d;
}

vec3 bg(vec2 p, vec3 col, bool isFinal){
    p*=20.;
    p.y*=0.6;
    p.y-=time*0.2;
    vec4 hgr = getHex(p);
    vec4 prevHgr = hgr;
    float n = Hash21(hgr.zw);
    
    float d = 10.;
    
    float d2 = 10.;
    if(n<0.3){
        d2 = pattern1(hgr.xy,n);
    } else if(n>=0.3 && n<0.6){
        d2 = pattern2(hgr.xy,n);
    } else {
        d = abs(sdHexagon(hgr.xy, 0.35))-0.05;
        if(!isFinal){
            float d3 = c25(hgr.xy*0.7);
            d = min(d,d3);
        } else {
            float d3 = animNumbers(hgr.xy*0.7,n*5.);
            d = min(d,d3);
        }
    }
    
    d = min(d,d2);
    d = max(-(abs(sdHexagon(hgr.xy, 0.46))-0.05),d);
    col = mix(col,vec3(0.5),S(d));
    return col;
}

vec2 sdRepeatNBetween(vec2 p, vec2 a, vec2 b, float r, int N) {
    vec2 dir = b - a;
    float len2 = dot(dir, dir);
    
    float k = dot(p - a, dir) / len2;
    float idx = floor(k * float(N - 1) + 0.5);
    idx = clamp(idx, 0.0, float(N - 1));
    vec2 center = a + dir * (idx / float(N - 1));
    return center;
}

float obstacles(vec2 p, vec2 a, vec2 b){
    float r = 0.25;
    float num = distance(a,b) / (2.0 * r);
    
    vec2 c = sdRepeatNBetween(p,a,b,r,int(ceil(num)));
    float d = obstacle(p,c,r);
    return d;
}

float centerObjects(vec2 p, vec2 a, vec2 b){
    float r = 1.5;
    float num = distance(a,b) / (2.0 * r);
    
    vec2 c = sdRepeatNBetween(p,a,b,r,int(ceil(num)));
    vec2 dir = b - a;
    float angle = atan(dir.y, dir.x)+radians(90.);
    float d = arrow(0.5*(p-c)*Rot(-angle));
    float m = length(p-a)-r;
    d = max(-m,d);
    m = length(p-b)-r;
    d = max(-m,d);
    return d;
}

float sideRepeatLines(vec2 p, float dist){
    vec2 prevP = p;
    p.y-=time*1.2;
    p.y = mod(p.y,1.2)-0.6;
    p*= SkewY(radians(-45.));
    float d = B(p,vec2(0.1,0.4));
    return max((abs(prevP.y)-dist),d);
}

float sideLines(vec2 p, float dist, float w){
    p.x = abs(p.x)-(w*0.25);
    float d = sideRepeatLines(p,dist*0.3);
    return d;
}

vec2 calcNormal(vec2 prev, vec2 current, vec2 next) {
    vec2 dir = vec2(0.);
    if (prev != current) dir += current - prev;
    if (next != current) dir += next - current;
    return normalize(vec2(-dir.y, dir.x));
}

vec3 courseMap(vec2 p, vec3 bgCol, vec3 col, float morph) {
    float d = B(p, vec2(mapSizeX, mapSizeY));
    col = mix(col, bgCol, S(d));
    d = max(d,drawHexBg(p*0.5));
    col = mix(col, vec3(1.), 1.-smoothstep(-0.01,0.01,d));
    
    float lsize = 1.7;
    float lsize2 = 2.2;
    const int pathCount = pathData.length();

    vec2 normals[pathCount];
    for (int i = 0; i < pathCount; i++) {
        vec2 prev = pathData[(i + pathCount - 1) % pathCount].xz;
        vec2 current = pathData[i].xz;
        vec2 next = pathData[(i + 1) % pathCount].xz;
        normals[i] = calcNormal(prev, current, next);
    }
    
    float d2 = 10.;
    float d3 = 10.;
    float d4 = 10.;
    float d5 = 10.;
    for (int i = 0; i < pathCount; i++) {
        vec2 a = pathData[i].xz;
        vec2 b = pathData[(i + 1) % pathCount].xz;

        vec2 nA = normals[i];
        vec2 nB = normals[(i + 1) % pathCount];

        float ld = sdPolygon( vec2[4](a + nA*lsize2, b + nB*lsize2, b - nB*lsize2,a - nA*lsize2),p);
        d2 = min(ld,d2);
        
        float od = obstacles(p, a + nA*lsize2, b + nB*lsize2);
        d3 = min(od,d3);
        od = obstacles(p, a - nA*lsize2, b - nB*lsize2);
        d3 = min(od,d3);
        
        od = centerObjects(p, a, b);
        d4 = min(od,d4);
        
        vec2 dir = b - a;
        float angle = atan(dir.y, dir.x)+radians(90.);   
        vec2 midP = p-((a+b)*0.5);
        float w = distance(a + nA*lsize2,a - nA*lsize2);
        od = sideLines(midP*Rot(-angle),distance(a,b),w);
        d5 = min(od,d5);
    }

    col = mix(col, vec3(0.05), mix(0.,S(abs(d2)-0.5),morph));
    col = mix(col, vec3(0.45), mix(0.,S(d2),morph)); // fix the small gaps.
    col = mix(col, vec3(0.3)+noise(p*20.*Rot(radians(45.)))*0.05, mix(0.,S(d2),morph));
    
    vec2 dir = pathData[1].xz - pathData[0].xz;
    float angle = atan(dir.y, dir.x)+radians(90.);    
    
    col = startLine((p-mix(pathData[0].xz,pathData[1].xz,0.12))*Rot(-angle),col,morph);
    
    col = mix(col, vec3(0.7), mix(0.,S(d3),morph));
    col = mix(col, vec3(0.7), mix(0.,S(d4),morph));
    col = mix(col, vec3(0.6), mix(0.,S(d5),morph));
    return col;
}

vec3 courseMapForUI(vec2 p, vec3 bgCol, vec3 col, vec3 camPos) {
    float lsize = 1.2;
    const int pathCount = pathData.length();

    float d = 10.;
    for (int i = 0; i < pathCount; i++) {
        vec2 a = pathData[i].xz;
        vec2 b = pathData[(i + 1) % pathCount].xz;

        float ld = lineTo(p, a, b) - lsize;
        d = min(d,ld);
    }

    col = mix(col, vec3(1.), S(d));
    col = mix(col, vec3(0.2), S(abs(d)-0.2));

    d = length(p - camPos.xz) - 0.8;
    col = mix(col, vec3(0.3), S(d));

    return col;
}

vec3 carDoor(vec2 p, vec3 col){
    vec2 prevP = p;
    float a = radians(45.);
    float d = B(p,vec2(0.013,0.15));
    p.x = abs(p.x);
    p.y = abs(p.y)-0.12;
    d = max(dot(p,vec2(cos(a),sin(a))),d);
    col = mix(col, vec3(0.),S(d));
    p = prevP;
    d = B(p,vec2(0.005,0.1));
    col = mix(col, vec3(0.9),S(d));
    return col;
}

vec3 carEngineFire(vec2 p, vec3 col){
    p.x*=4.;
    p.y*=-0.9;
    p.x+=noise(p*Rot(radians(time*100.))*60.)*0.08;
    float d = Tri(p,vec2(0.1));
    col = mix(col, vec3(0.5),1.-smoothstep(0.,0.05,d));
    return col;
}

vec3 carMain(vec2 p, vec3 col, float leftVal, float rightVal){
    vec2 prevP = p;
     
    float a = radians(45.);
    float d = B(p-vec2(0.,0.05),vec2(0.08,0.1));
    p.x = abs(p.x);
    p.y-=0.19;
    d = max(dot(p,vec2(cos(a),sin(a))),d);
    p = prevP;
    float d2 = B(p,vec2(0.17,0.06));
    d = min(d,d2);
    
    a = radians(-45.);
    p.y+=0.05;
    d2 = B(p,vec2(0.07,0.06));
    p.x = abs(p.x);
    p.y+=0.11;
    d2 = max(dot(p,vec2(cos(a),sin(a))),d2);
    d = min(d,d2);
    
    p = prevP;
    p.x = abs(p.x)-0.12;
    a = radians(-45.);
    p.y+=0.035;
    d2 = B(p,vec2(0.05,0.06));
    p.x = abs(p.x);
    p.y+=0.08;
    d2 = max(dot(p,vec2(cos(a),sin(a))),d2);
    d = min(d,d2);
    
    p = prevP;
    p.x = abs(p.x)-0.12;
    a = radians(45.);
    p.y-=0.03;
    d2 = B(p,vec2(0.035,0.06));
    p.x = abs(p.x);
    p.y-=0.075;
    d2 = max(dot(p,vec2(cos(a),sin(a))),d2);
    d = min(d,d2);
    
    col = mix(col, vec3(0.),S(d));
    
    p = prevP;
    p.y-=0.01;
    a = radians(45.);
    d = B(p,vec2(0.05,0.035));
    p.x = abs(p.x)-0.06;
    p.y = abs(p.y);
    d = max(dot(p,vec2(cos(a),sin(a))),d);
    
    p = prevP;
    p.y+=0.05;
    p.y = abs(p.y)-0.008;
    d2 = B(p,vec2(0.05,0.005));
    d = min(d,d2);
    
    p = prevP;
    p.y+=0.082;
    a = radians(-45.);
    d2 = B(p,vec2(0.06,0.012));
    p.x = abs(p.x)-0.062;
    d2 = max(dot(p,vec2(cos(a),sin(a))),d2);
    
    p = prevP;
    p.y+=0.07;
    a = radians(-45.);
    float mask = B(p,vec2(0.05,0.012));
    p.x = abs(p.x)-0.055;
    mask = max(dot(p,vec2(cos(a),sin(a))),mask);
    
    d2 = max(-mask,d2);
    d = min(d,d2);
    
    p = prevP;
    p.y-=0.095;
    a = radians(45.);
    d2 = B(p,vec2(0.06,0.04));
    p.x = abs(p.x)-0.07;
    d2 = max(dot(p,vec2(cos(a),sin(a))),d2);
    
    p = prevP;
    p.y-=0.06;
    a = radians(45.);
    mask = B(p,vec2(0.045,0.016));
    p.x = abs(p.x)-0.045;
    mask = max(dot(p,vec2(cos(a),sin(a))),mask);
    
    d2 = max(-mask,d2);
    d = min(d,d2);
    
    p = prevP;
    p.x = abs(p.x)-0.12;
    p.y+=0.035;
    a = radians(45.);
    d2 = B(p,vec2(0.032,0.045));
    p.x = abs(p.x)-0.055;
    p.y = abs(p.y);
    d2 = max(dot(p,vec2(cos(a),sin(a))),d2);
    d = min(d,d2);
    
    p = prevP;
    p.x = abs(p.x)-0.12;
    p.y-=0.07;
    d2 = B(p,vec2(0.025,0.011));
    p.x = abs(p.x)-0.02;
    d2 = max(dot(p,vec2(cos(a),sin(a))),d2);
    d = min(d,d2);
    
    p = prevP;
    p.x = abs(p.x)-0.12;
    
    p.y-=0.027;
    a = radians(45.);
    d2 = B(p,vec2(0.05,0.02));
    p.x = abs(p.x)-0.04;
    d2 = max(dot(p,vec2(cos(a),sin(a))),d2);
    
    p = prevP;
    p.x = abs(p.x)-0.12;
    p.y-=0.008;
    a = radians(45.);
    mask = B(p,vec2(0.04,0.016));
    p.x = abs(p.x)-0.03;
    mask = max(dot(p,vec2(cos(a),sin(a))),mask);
    
    d2 = max(-mask,d2);
    d = min(d,d2);
    
    col = mix(col, vec3(0.9),S(d));
    
    p = prevP;
    
    float targetY = 0.03;
    
    // left door
    col = carDoor(p-vec2(-0.18,leftVal*targetY),col);
    
    // right door
    col = carDoor(p-vec2(0.18,rightVal*targetY),col);
    
    p.x = abs(p.x)-0.13;
    p.y+=0.2;
    col = carEngineFire(p,col);
    return col;
}

vec3 car(vec2 p, vec3 col, float leftVal, float rightVal){
    vec2 prevP = p;
    p.x*= 0.5;
    p.y*= 2.5;
    p.y+=0.25;
    float d =  length(p)-0.1;
    col = mix(col, col*vec3(0.7),S(d));
    p = prevP;
    
    p.y+=sin(time*5.)*0.01;
    float targetSknewX = 10.;
    p*=SkewX(radians(leftVal*targetSknewX));
    p*=SkewX(radians(rightVal*-targetSknewX));
    col = carMain(p-vec2(0.0,0.03),col,leftVal,rightVal);
    
    return col;
}

vec3 carEnergy(vec2 p, vec3 col){
    vec2 prevP = p;
    p.x*= 0.5;
    p.y*= 2.5;
    p.y+=time*2.;
    p.y = mod(p.y,0.22)-0.11;
    float d =  abs(length(p)-0.1)-0.015;
    p = prevP;
    float mask = B(p-vec2(0.0,0.1),vec2(0.25,0.4));
    vec2 cp = p-vec2(0.0,-0.35);
    cp.y*=2.;
    float d2 = length(cp)-0.25;
    mask = min(mask,d2);
    p = prevP;
    d = max(mask,d);
    col = mix(col, col*vec3(2.),S(d));
    return col;
}

float carEffectParts(vec2 p){
    vec2 prevP = p;
    p.x*=3.;
    float d = length(p)-0.4;
    return d;
}

vec3 carEffect(vec2 p, vec2 p2, vec3 col){
    p.y+=time*2.;
    vec2 prevP = p;
    p*=6.;
    vec2 id = floor(p);
    vec2 gr = fract(p)-0.5;
    float n = Hash21(id);
    
    float d = carEffectParts(gr);
    if(n<0.5)d = 10.;
    d = max((length(p2)-0.22),d);
    col = mix(col,col*vec3(2.),S(d));

    return col;
}

float cubicInOut(float t) {
  return t < 0.5
    ? 4.0 * t * t * t
    : 0.5 * pow(2.0 * t - 2.0, 3.0) + 1.0;
}

float getTime(float t, float duration){
    return clamp(t,0.0,duration)/duration;
}

vec3 effectOverlay1(vec2 p, vec2 p2, vec3 col){
    vec2 id = floor(p);
    vec2 gr = fract(p)-0.5;
    float n = Hash21(id);
    float d = (n<0.5) ? 10. :B(gr,vec2(0.5*n,0.05*n));
    vec3 ecol = col+(vec3(mix(0.0,1.,gr.x+0.5))* length(p2)-0.1);
    col = mix(col,ecol,S(d));
    return col;
}

vec3 effectOverlay2(vec2 p, vec2 p2, vec3 col){
    vec2 id = floor(p);
    vec2 gr = fract(p)-0.5;
    float n = Hash21(id);
    gr *= n;
    float d = (n<0.5) ? 10. : length(gr)-0.1;
    vec3 ecol = col+(vec3(1.0)* length(p2)-0.2);
    col = mix(col,ecol,S(d));
    return col;
}

vec3 windEffect(vec2 p, vec3 col, float alpha, float s){
    vec2 prevP = p;
    p*=s;
    p.y+=time*5.;
    vec2 id = floor(p);
    vec2 gr = fract(p)-0.5;
    float n = Hash21(id);
    gr *= n*2.;
    gr.x*=2.;
    float d = (n<0.5) ? 10. : arrow(gr);
    p = prevP;
    d = max(B(p, vec2(mapSizeX, mapSizeY)),d);
    col = mix(col,col+vec3(alpha),S(d));
    return col;
}

vec3 ui(vec2 p, vec3 col){
    vec2 prevP = p;
    float x = 0.58;
    float d = times(p-vec2(x,0.2));
    col = mix(col,vec3(1.),S(d));
    d = B(p-vec2(x,0.275),vec2(0.2,0.005));
    col = mix(col,vec3(1.),S(d));
    d = speedMeter(p-vec2(x+0.11,0.33));
    col = mix(col,vec3(1.),S(d));
    d = power(p-vec2(x,0.41));
    col = mix(col,vec3(1.),S(d));
    return col;
}

vec3 drawRaceScene(vec2 p, vec3 col){
    float speed = 0.55; 
    float totalSegs = float(pathData.length());
    
    float firstSceneTotal = 1.5;
    float endSceneTotal = 3.;
    float totalLaps = 2.0;
    float raceTotal = totalSegs*totalLaps;
    float sceneTotal = firstSceneTotal+raceTotal+endSceneTotal;
    float t = time*speed;
    float scene = mod(t,sceneTotal);
    
    int raceRound = 1;
    int effect = 0;
    float initialUiX = 0.6;
    bool isFinal = false;
    if(scene<sceneTotal){
        float f = mod(scene, firstSceneTotal+totalSegs)-firstSceneTotal;
        if(scene>=firstSceneTotal+totalSegs && scene<firstSceneTotal+raceTotal){
            f = mod(scene, firstSceneTotal+raceTotal)-(firstSceneTotal+totalSegs);
        }
        int seg = int(floor(f));
        float segT = fract(f);

        float endAnimStart = firstSceneTotal+raceTotal+(endSceneTotal-2.);
        float initialCarY = -0.5;
        float initialRot = radians(90.);
        float initialHeight = -8.;
        float initialMapX = -40.;
        float courseMorph = 0.;
        float carScale = 1.;
        float easeValue = 0.;
        float duration = 1.;
        float time = scene;
        if(scene<firstSceneTotal+0.1){
            time = getTime(time,duration);
            float anim = cubicInOut(time);
            easeValue = 90.-(anim*90.);
            initialHeight = -8.+(anim*8.);
            initialRot = radians(easeValue);
            initialCarY = -0.5+(anim*0.5);
            initialUiX= 0.6-(anim*0.6);
            initialMapX = -40.+(anim*40.);
            courseMorph = anim;
        } else if(scene >=firstSceneTotal+raceTotal && scene < endAnimStart){
            initialRot = 0.0;
            initialHeight = 0.0;
            initialUiX = 0.0;
            initialMapX = 0.0;
            time = getTime(time-(firstSceneTotal+raceTotal),duration);
            float anim = time;
            initialCarY = (anim*0.25);
            carScale = 1.+(anim*0.5);
            courseMorph = 1.;
        } else if(scene >= endAnimStart && scene < sceneTotal){
            time = getTime(time-endAnimStart,duration*0.7);
            float anim = cubicInOut(time);
            easeValue = anim*90.;
            initialHeight = -(anim*8.);
            initialRot = radians(easeValue);
            initialCarY = 0.25-(anim*0.75);
            initialUiX= (anim*0.6);
            initialMapX = -(anim*40.);
            carScale = 1.5-(anim*0.5);
            courseMorph = 1.-anim;
        }
        
        if(scene>=firstSceneTotal+0.1 && scene<firstSceneTotal+raceTotal){
            initialRot = 0.0;
            initialHeight = 0.0;
            initialCarY = 0.0;
            initialUiX = 0.0;
            initialMapX = 0.0;
            courseMorph = 1.;
        }
        
        if(scene<firstSceneTotal){
            seg = 0;
            segT = 0.0;
        } else if(scene>=firstSceneTotal+raceTotal){
            seg = 0;
            segT = 0.0;
        }
        
        // display race round
        if(scene<firstSceneTotal-0.25){
            raceRound = -1;
        } else if(scene>=firstSceneTotal-0.25 && scene<=firstSceneTotal+0.3){
            raceRound = 1;
        } else if(scene>=firstSceneTotal+totalSegs-0.25 && scene<=firstSceneTotal+totalSegs+0.4){
            raceRound = 2;
        } else if(scene>=firstSceneTotal+raceTotal && scene<endAnimStart){
            raceRound = 3;
        } else {
            raceRound = 0;
        }
        
        // check final lap
        if(scene>=firstSceneTotal+totalSegs){
            isFinal = true;
        }
        
        // effect
        if(scene>=firstSceneTotal+(totalSegs-1.0) && scene < firstSceneTotal+(totalSegs-0.25)){
            effect = 1;
        } else if(scene>=firstSceneTotal+(raceTotal-1.0) && scene < firstSceneTotal+(raceTotal-0.25)){
            effect = 2;
        }
        
        int segs = int(totalSegs);
        int i0 = seg;
        int i1 = (seg + 1) % segs;
        int i2 = (seg + 2) % segs;

        vec3 A = pathData[i0];
        vec3 B = pathData[i1];
        vec3 C = pathData[i2];

        vec3 camPos = mix(A, B, segT);

        float yawAB = yawBetweenPoints(A, B);
        float yawBC = yawBetweenPoints(B, C);

        float blendT = smoothstep(0.7, 1.0, segT);
        float yaw = lerpAngle(yawAB, yawBC, blendT);

        float pitchAB = pitchBetweenPoints(A, B);
        float pitchBC = pitchBetweenPoints(B, C);
        float pitch = lerpAngle(pitchAB, pitchBC, blendT); 

        mat3 camRotation = rotY3(yaw) * rotX3((pitch+radians(10.))+initialRot);

        vec3 ray = normalize(vec3(p, 1.0));
        ray = camRotation * ray;

        float z = ray.z;
        vec2 proj = ray.xy / z;

        float d = 10.;

        float groundHeight = -0.5+initialHeight;
        float t = (groundHeight - camPos.y) / ray.y;
        vec3 hit = camPos + ray * t;

        // render background
        vec3 ray2 = ray;
        vec3 r = normalize(ray);
        r.x=abs(r.x);
        float newX = atan(r.x, r.z) / (2.0*PI) + 0.5;
        float newY = asin(clamp(r.y, -1.0, 1.0)) / PI + 0.5;
        vec2 bgp = vec2(newX,newY);
        col = bg(vec2(newX,newY),col,isFinal);

        // render course map
        if(t > 0.0) {
            col = courseMap(hit.xz,vec3(0.15),col,courseMorph);
            
            if(scene>=firstSceneTotal-0.25 && scene<endAnimStart){
                col = windEffect(hit.xz,col,0.05,0.9);
            }
        } else {
            groundHeight = -3.;
            t = (groundHeight - camPos.y) / ray.y;
            hit = camPos + ray * t;
            
            if(scene>=firstSceneTotal-0.25 && scene<endAnimStart){
                col = windEffect(hit.xz*0.8,col,0.3,0.5);
            }
        }

        // render ui course map
        float spriteZ = 7.0;
        col = courseMapForUI((p*90.)-vec2(-59.+initialMapX,-25.),vec3(1.),col,camPos);

        // render effets
        vec2 ep = ray.xy;
        ep.x = p.x;
        ep*=Rot(radians(3.*time*(effect == 1?1.:30.)));
        ep = PUV(ep);
        ep.x-=time*5.;
        ep*=2.54;
        if(effect == 1){
            col = effectOverlay1(ep,p,col);
        } else if(effect == 2){
            col = effectOverlay2(ep,p,col);
        }

        // render car
        float yawDelta = yawBC - yawAB;
        yawDelta = mod(yawDelta + PI, PI*2.) - PI;

        float leftVal  = yawDelta <  -0.001 ? 1.0 : 0.0;
        float rightVal = yawDelta > 0.001 ? 1.0 : 0.0;

        float turnBlend = smoothstep(0.5, 1.0, segT);
        leftVal  *= turnBlend;
        rightVal *= turnBlend;  

        col = car((p- vec2(0.,-0.3+initialCarY))*carScale,col,leftVal,rightVal);
        
        if(scene>=firstSceneTotal+totalSegs+1. && scene<firstSceneTotal+totalSegs+1.7){
            col = carEnergy(p,col);
        }
        
        if(scene>=firstSceneTotal+totalSegs+1.7 && scene<firstSceneTotal+totalSegs+7.){
            col = carEffect(getSphereMap(p-vec2(0.,-0.25),4.),p-vec2(0.,-0.25),col);
        }
    }
    
    // display round text
    if(raceRound == -1){
        // count down
        float count = 3.0-((scene/firstSceneTotal-0.25)*3.0);
        float d = drawNumbers(p,int(count));
        col = mix(col,vec3(0.2),1.-smoothstep(0.,0.025,d));
        col = mix(col,vec3(1.),S(d));
        col = mix(col,vec3(0.),S(abs(d)-0.003));
    } else if(raceRound == 1){
        // GO
        float d = go(p);
        col = mix(col,vec3(1.),S(d));
        col = mix(col,vec3(0.),S(abs(d)-0.003));
    } else if(raceRound == 2){
        // final lap
        float d = finallap(p);
        col = mix(col,vec3(1.),S(d));
        col = mix(col,vec3(0.),S(abs(d)-0.003));
    } else if(raceRound == 3){
        // goal
        float d = goal(p);
        col = mix(col,vec3(1.),S(d));
        col = mix(col,vec3(0.),S(abs(d)-0.003));
    }
    
    // render ui
    col = ui(p-vec2(initialUiX,0.0),col);
    
    return col;
}

void main( void ){
    vec2 p = (gl_FragCoord.xy-.5*resolution.xy)/resolution.y;

    vec3 col = vec3(0.0);
    col = drawRaceScene(p,col);
    
    fragColor = vec4(vec3(col), 1.0);
}