//Marble Race in Truchet City
precision highp float;
uniform vec2 resolution;
uniform vec2 mouse;
uniform float time;
uniform sampler2D backbuffer;
out vec4 outColor;

#define pi acos(-1.)
const float tau=2.*pi;
#define rot(spin)mat2(cos(spin),sin(spin),-sin(spin),cos(spin))


const bool ONGRID = false;
const bool ONRACEORDER = false;
const bool ONDRAWCENTER=false;
const float COURCEID = 217.;

const float onBoardCameraProb=.3;
const bool onBoardCamera=false;
const bool backCamera=false;

const int RACERNUM = 8;

// LAPDATA
const float ALLLAP = 50.;
const float BEFORELAP = 5.;
const float STARTLAP = 1.;
const float AFTERLAP = 5.;
const float ENDLAP = 5.;
const float RACELAP = ALLLAP - BEFORELAP - AFTERLAP - ENDLAP;

// スタート時の逆流を防ぐ応急処理
float extraMileage = 1.75;

float progress;
float beforeProgress;
float startProgress;
float finishProgress;

const float marbleSize = .008;
const float roadWidth = .1;

const float cityHeight = 0.05;
const float cityScale = 32.;

#define STARTPOSITION vec2(0.,0.)
#define INITIALPOS vec2(0.,.5)+STARTPOSITION
#define INITIALDIR vec2(1.,0.)


const float fogDensity=1.5;
const float fogDistance=0.1;
const vec3 fogColor=vec3(.34,.37,.4);

const float windowSize=.3/cityScale;
const float windowDivergence=.2/cityScale;
const vec3 windowColor=vec3(.1,.2,.5);

const float streetDistance=.015;
const vec3 streetColor=vec3(4.,8.,10.);

const float beaconProb=.003;
const float beaconFreq=.6;
const vec3 beaconColor=vec3(1.5,.2,0.);
const vec3 beaconGreenColor=vec3(.2,1.5,0.);

const vec3 roadGlow=vec3(1,.3,.2)*2E-5;

vec4 RACERNUMCOLOR[8]=vec4[](
   vec4(1.,0.,0.,1.),// Red
   vec4(0.,1.,0.,1.),// Green
   vec4(0.,0.,1.,1.),// Blue
   vec4(1.,1.,0.,1.),// Yellow
   vec4(1.,0.,1.,1.),// Magenta
   vec4(0.,1.,1.,1.),// Cyan
   vec4(.5,.5,.5,1.),// Gray
   vec4(1.,1.,1.,1.)// White
);

//   _ __   ___ (_)___  ___
//  | '_ \ / _ \| / __|/ _ \
//  | | | | (_) | \__ \  __/
//  |_| |_|\___/|_|___/\___|
float hash1(vec2 p2){
   p2=fract(p2*vec2(5.3983,5.4427));
   p2+=dot(p2.yx,p2.xy+vec2(21.5351,14.3137));
   return fract(p2.x*p2.y*95.4337);
}

float hash1(vec2 p2,float p){
   vec3 p3=fract(vec3(5.3983*p2.x,5.4427*p2.y,6.9371*p));
   p3+=dot(p3,p3.yzx+19.19);
   return fract((p3.x+p3.y)*p3.z);
}

vec2 hash2(vec2 p2){
   vec3 p3=fract(vec3(5.3983*p2.x,5.4427*p2.y,6.9371*p2.x));
   p3+=dot(p3,p3.yzx+19.19);
   return fract((p3.xx+p3.yz)*p3.zy);
}

vec2 hash2(vec2 p2,float p){
   vec3 p3=fract(vec3(5.3983*p2.x,5.4427*p2.y,6.9371*p));
   p3+=dot(p3,p3.yzx+19.19);
   return fract((p3.xx+p3.yz)*p3.zy);
}

vec3 hash3(vec2 p2){
   vec3 p3=fract(vec3(p2.xyx)*vec3(5.3983,5.4427,6.9371));
   p3+=dot(p3,p3.yxz+19.19);
   return fract((p3.xxy+p3.yzz)*p3.zyx);
}

float noise1(vec2 p){
   vec2 i=floor(p);
   vec2 f=fract(p);
   vec2 u=f*f*(3.-2.*f);
   return mix(mix(hash1(i+vec2(0.,0.)),
   hash1(i+vec2(1.,0.)),u.x),
   mix(hash1(i+vec2(0.,1.)),
   hash1(i+vec2(1.,1.)),u.x),u.y);
}

float Hash21(vec2 p){
   p=fract(p*vec2(234.24,234.535));
   p+=dot(p,p+34.23+COURCEID);
   return fract(p.x*p.y);
}

// Simplex 2D noise
vec3 permute(vec3 x){return mod(((x*34.)+1.)*x,289.);}

float snoise(vec2 v){
   const vec4 C=vec4(.211324865405187,.366025403784439,
   -.577350269189626,.024390243902439);
   vec2 i=floor(v+dot(v,C.yy));
   vec2 x0=v-i+dot(i,C.xx);
   vec2 i1;
   i1=(x0.x>x0.y)?vec2(1.,0.):vec2(0.,1.);
   vec4 x12=x0.xyxy+C.xxzz;
   x12.xy-=i1;
   i=mod(i,289.);
   vec3 p=permute(permute(i.y+vec3(0.,i1.y,1.))
   +i.x+vec3(0.,i1.x,1.));
   vec3 m=max(.5-vec3(dot(x0,x0),dot(x12.xy,x12.xy),
   dot(x12.zw,x12.zw)),0.);
   m=m*m;
   m=m*m;
   vec3 x=2.*fract(p*C.www)-1.;
   vec3 h=abs(x)-.5;
   vec3 ox=floor(x+.5);
   vec3 a0=x-ox;
   m*=1.79284291400159-.85373472095314*(a0*a0+h*h);
   vec3 g;
   g.x=a0.x*x0.x+h.x*x0.y;
   g.yz=a0.yz*x12.xz+h.yz*x12.yw;
   return 130.*dot(m,g);
}

//   _____           _
//  |  ___|__  _ __ | |_
//  | |_ / _ \| '_ \| __|
//  |  _| (_) | | | | |_
//  |_|  \___/|_| |_|\__|
// kinankomoti font_logging https://www.shadertoy.com/view/mdVSWz
#define FontWidth 8
#define FontHeight 8
#define LineMaxLength 40

ivec2 font_data[94]=ivec2[](
   //0
   ivec2(0x00000000,0x00000000),//space

   //1~10
   ivec2(0x7e91897e,0x00000000),//0
   ivec2(0x01ff4121,0x00000000),//1
   ivec2(0x71898543,0x00000000),//2
   ivec2(0x6e919142,0x00000000),//3
   ivec2(0x08ff4838,0x00000000),//4
   ivec2(0x8e9191f2,0x00000000),//5
   ivec2(0x0e91916e,0x00000000),//6
   ivec2(0xc0b08f80,0x00000000),//7
   ivec2(0x6e91916e,0x00000000),//8
   ivec2(0x6e919162,0x00000000),//9

   //11~36
   ivec2(0x1e11110e,0x00000001),//a
   ivec2(0x0e11117f,0x00000000),//b
   ivec2(0x0a11110e,0x00000000),//c
   ivec2(0x7f11110e,0x00000000),//d
   ivec2(0x0815150e,0x00000000),//e
   ivec2(0x48483f08,0x00000000),//f
   ivec2(0x3e494930,0x00000000),//g
   ivec2(0x0708087f,0x00000000),//h
   ivec2(0x012f0900,0x00000000),//i
   ivec2(0x5e111102,0x00000000),//j
   ivec2(0x000b047f,0x00000000),//k
   ivec2(0x017f4100,0x00000000),//l
   ivec2(0x0807080f,0x00000007),//m
   ivec2(0x0708080f,0x00000000),//n
   ivec2(0x06090906,0x00000000),//o
   ivec2(0x1824243f,0x00000000),//p
   ivec2(0x3f242418,0x00000000),//q
   ivec2(0x0010081f,0x00000000),//r
   ivec2(0x0012150d,0x00000000),//s
   ivec2(0x11113e10,0x00000000),//t
   ivec2(0x0f01010e,0x00000000),//u
   ivec2(0x000e010e,0x00000000),//v
   ivec2(0x010e010e,0x0000000f),//w
   ivec2(0x0a040a11,0x00000011),//x
   ivec2(0x3e090930,0x00000000),//y
   ivec2(0x00191513,0x00000000),//z

   //36~63
   ivec2(0x7f88887f,0x00000000),//A
   ivec2(0x6e9191ff,0x00000000),//B
   ivec2(0x4281817e,0x00000000),//C
   ivec2(0x7e8181ff,0x00000000),//D
   ivec2(0x919191ff,0x00000000),//E
   ivec2(0x909090ff,0x00000000),//F
   ivec2(0x4685817e,0x00000000),//G
   ivec2(0xff1010ff,0x00000000),//H
   ivec2(0x0081ff81,0x00000000),//I
   ivec2(0x80fe8182,0x00000000),//J
   ivec2(0x413608ff,0x00000000),//K
   ivec2(0x010101ff,0x00000000),//L
   ivec2(0x601060ff,0x000000ff),//M
   ivec2(0x0c1060ff,0x000000ff),//N
   ivec2(0x7e81817e,0x00000000),//O
   ivec2(0x609090ff,0x00000000),//P
   ivec2(0x7f83817e,0x00000001),//Q
   ivec2(0x619698ff,0x00000000),//R
   ivec2(0x4e919162,0x00000000),//S
   ivec2(0x80ff8080,0x00000080),//T
   ivec2(0xfe0101fe,0x00000000),//U
   ivec2(0x0e010ef0,0x000000f0),//V
   ivec2(0x031c03fc,0x000000fc),//W
   ivec2(0x340834c3,0x000000c3),//X
   ivec2(0x300f30c0,0x000000c0),//Y
   ivec2(0xe1918d83,0x00000081),//Z

   //63~
   ivec2(0x00007d00,0x00000000),//!
   ivec2(0x60006000,0x00000000),//"
   ivec2(0x3f123f12,0x00000012),//#
   ivec2(0x52ff5224,0x0000000c),//$
   ivec2(0x33086661,0x00000043),//%
   ivec2(0x374d5926,0x00000001),//&
   ivec2(0x00006000,0x00000000),//'
   ivec2(0x0081423c,0x00000000),//(
   ivec2(0x003c4281,0x00000000),//)
   ivec2(0x00143814,0x00000000),//*
   ivec2(0x00103810,0x00000000),//+
   ivec2(0x00020100,0x00000000),//,
   ivec2(0x08080808,0x00000000),//-
   ivec2(0x00000100,0x00000000),//.
   ivec2(0x30080601,0x00000040),///
   ivec2(0x00240000,0x00000000),//:
   ivec2(0x00240200,0x00000000),//;
   ivec2(0x41221408,0x00000000),//<
   ivec2(0x00141414,0x00000000),//=
   ivec2(0x08142241,0x00000000),//>
   ivec2(0xa999423c,0x0000007c),//@
   ivec2(0x008181ff,0x00000000),//[
   ivec2(0x06083040,0x00000001),//\
   ivec2(0x00000000,0x00000000),//] 何故か表示されない
   ivec2(0x00ff8181,0x00000000),//]
   ivec2(0x20402010,0x00000010),//^
   ivec2(0x01010101,0x00000000),//_
   ivec2(0x40408080,0x00000000),//`
   ivec2(0x41413608,0x00000000),//{
   ivec2(0x00ff0000,0x00000000),//|
   ivec2(0x08364141,0x00000000),//}
   ivec2(0x08101008,0x00000010)//~

);

vec3 font(vec2 uv,int id){
   vec2 uv1=uv;
   uv=uv*8.;
   ivec2 texel=ivec2(uv);
   int bit_offset=texel.x*FontWidth+texel.y;

   int s,t;
   s=font_data[id].x;
   t=font_data[id].y;

   int tex=0;

   if(bit_offset<=31){
       s=s>>bit_offset;
       s=s&0x00000001;
       tex=s;
   }
   else{
       t=t>>(bit_offset-32);
       t=t&0x00000001;
       tex=t;
   }

   tex=(abs(uv1.x-.5)<.5&&abs(uv1.y-.5)<.5)?tex:0;
   return vec3(tex);
}


//           _  __
//   ___  __| |/ _|
//  / __|/ _` | |_
//  \__ \ (_| |  _|
//  |___/\__,_|_|
bool drawCircle(vec2 uv,vec2 pos){
   float posPoint=.075-length(pos-uv);
   return ceil(posPoint)==1.;
}

float calculateGridLine(vec2 uv,float grid_size,float line_width){

   // グリッドの線を計算
   float line_x=step(grid_size-line_width,mod(uv.x-line_width/2.,grid_size));
   float line_y=step(grid_size-line_width,mod(uv.y-line_width/2.,grid_size));

   float line=line_x+line_y;

   return line;
}

float sdSphere(vec3 p,float r)
{
   return length(p)-r;
}

//    ____ _____ _     _
//   / ___| ____| |   | |
//  | |   |  _| | |   | |
//  | |___| |___| |___| |___
//   \____|_____|_____|_____|
// inspired by 2d truchet traveler abje https://www.shadertoy.com/view/4tfcDl
int getcell(vec2 pos){
   return int(floor(Hash21(mod(pos,vec2(64.)))*3.));
}

float passedCellNum(float mileage){
   // mileage=mod(mileage,128.);
   return floor(mileage);
}

struct TruchetData{
   vec2 pos;
   vec2 dir;
   vec2 floorpos;
};

TruchetData allSkippedData[128];
int lastSkippedDataIndex;

#define EXTRACELL 5.
void setSkipTruchetData(vec2 pos,vec2 dir, vec2 floorpos, float mileage){
   for(float i=0.;i<passedCellNum(RACELAP) + EXTRACELL;i++){
       // for(float i=0.;i<floor(fract(time*.01)*100.);i++){
       pos+=dir*.5;// centerPosがタイルの中央に乗る
       int celltype=getcell(floorpos);//現在の位置のセルタイプを取得

       // セルタイプが0の場合、左に曲がるよう方向を転換
       if(celltype==0){
           dir=dir.yx;
       // セルタイプが1の場合、右に曲がるよう方向を転換
       }else if(celltype==1){
           dir=-dir.yx;
       }
       // セルタイプが2の場合、方向を変えずに進むため方向転換無し

       floorpos+=dir;// 現在のタイル位置を次のタイル位置に更新
       pos+=dir*.5;// centerPosが次のタイルの端に乗る

       allSkippedData[int(i)]=TruchetData(pos,dir,floorpos);
   }
}

vec2 getCachedSkipTruchetPos(inout vec2 pos,inout vec2 dir,inout vec2 floorpos, float mileage){
   int index = int(passedCellNum(mileage));
   TruchetData data=allSkippedData[index];
   pos=data.pos;
   dir=data.dir;
   floorpos=data.floorpos;
   return pos;
}

vec4 getNowOnTruchetPos(inout vec2 pos,inout vec2 dir,inout vec2 floorpos,float mileage,float sidePosition){
   float multiplier=1.;

   int celltype=getcell(floorpos);
   vec2 nextDir;
   if(celltype==0){
       nextDir=dir.yx;
   }else if(celltype==1){
       nextDir=-dir.yx;
   }

   float corner=dir.x*nextDir.y-dir.y*nextDir.x;

   // 仕組みがわからないですが観察結果から、横移動の場合は左が逆転する
   float side = 1.;
   if(dir.x!=0.) side = -1.;

   // affectが正なら右に移動
   float affect = sidePosition*(roadWidth*5.);
   // 左回転
   if(0.<corner){
       pos+=dir.yx * affect * .5 * side;
       multiplier=1.+affect;
   }
   // 右回転
   if(corner<0.){
       pos+=dir.yx * affect * .5 * side;
       multiplier=1.-affect;
   }
   // 直進
   if(corner==0.){
       //dirのy,xを入れ替えたものに、xに-1をかけたものが左になる
       pos+=dir.yx * vec2(1,-1) * affect * .5;
   }


   // mileageに応じて位置調整
   pos+=dir*sin(fract(mileage)*pi*.5)*.5 * multiplier;

   vec2 dirForRacingObject=dir;
   if(celltype==0){
       dirForRacingObject*=rot(dot(abs(dir),vec2(-1.,1.))*fract(mileage)*pi*.5);
       dir=dir.yx;
   }else if(celltype==1){
       dirForRacingObject*=rot(dot(abs(dir),vec2(1.,-1.))*fract(mileage)*pi*.5);
       dir=-dir.yx;
   }
   pos+=dir*(.5-cos(fract(mileage)*pi*.5)*.5) * multiplier;
   return vec4(pos,dirForRacingObject);
}

//   ____
//  |  _ \ __ _  ___ ___ _ __
//  | |_) / _` |/ __/ _ \ '__|
//  |  _ < (_| | (_|  __/ |
//  |_| \_\__,_|\___\___|_|
struct Racer{
   vec2 pos;
   vec2 dirForRacingObject;
   vec4 color;
   float ID;
   float mileage;
};

Racer createRacerFromTruchet(float mileage,float sidePosition, vec4 color, float ID){
   vec2 racerPos;
   vec2 dir;
   vec2 floorpos;
   racerPos=getCachedSkipTruchetPos(racerPos,dir,floorpos,mileage);
   vec4 getNowOnTruchetPosResult = getNowOnTruchetPos(racerPos,dir,floorpos,mileage,sidePosition);
   return Racer(getNowOnTruchetPosResult.xy,getNowOnTruchetPosResult.zw,color,ID, mileage);
}

//   ____             _
//  / ___|  ___  _ __| |_
//  \___ \ / _ \| '__| __|
//   ___) | (_) | |  | |_
//  |____/ \___/|_|   \__|
// バブルソートで任意の数の構造体配列をソートする関数
void bubbleSort(inout Racer arr[RACERNUM],int size){
   for(int i=0;i<size-1;i++){
       for(int j=0;j<size-i-1;j++){
           if(arr[j].mileage<arr[j+1].mileage){
               // 値を入れ替える
               Racer temp=arr[j];
               arr[j]=arr[j+1];
               arr[j+1]=temp;
           }
       }
   }
}

//   ____
//  / ___|  ___ ___ _ __   ___
//  \___ \ / __/ _ \ '_ \ / _ \
//   ___) | (_|  __/ | | |  __/
//  |____/ \___\___|_| |_|\___|
float getRoadOrCity(vec2 block, float roadWidth){
   // ■ タイルごとのUV生成
   vec2 flooruv=floor(block);
   vec2 uvOfTile=block-flooruv-.5;
   int celltype=getcell(flooruv.xy);

   // ■ 道の描画
   //uvから道のもとになるlenを作る
   vec2 uvOfTileForRoad=uvOfTile;
   if(celltype==0)uvOfTileForRoad*=vec2(1.,-1.);
   uvOfTileForRoad*=step(0.,uvOfTileForRoad.x+uvOfTileForRoad.y)*2.-1.;
   float len;
   if(celltype==2){
       len=min(abs(uvOfTileForRoad.x),abs(uvOfTileForRoad.y));
   }else{
       len=length(uvOfTileForRoad-.5)-.5;
   }

   //道を描画
   float roadSize=(abs(len)-roadWidth)*resolution.y*.1;
   float clampedRoad=clamp(roadSize,0.,1.);

   return clampedRoad;
}

// inspired by Glow City mhnewman https://www.shadertoy.com/view/XlsyWB
#define NOHIT 0.
#define HIT_CITY 1.
#define HIT_ROAD 2.

struct CityResult{
   float distance;
   float beacon;
   float face;
   float hittedTarget;
   float distanceFromEye;
   vec3 hitPos;
};

CityResult cityRay(vec3 eye,vec3 ray){
   eye.xyz = eye.xzy;
   ray.xyz = ray.xzy;
   vec2 block=floor(eye.xy*cityScale)/cityScale;
   vec3 ri=1./ray;
   vec3 rs=sign(ray);
   vec3 side=.5+.5*rs;
   vec2 ris=ri.xy*rs.xy;
   vec2 dis=(block-eye.xy+.5/cityScale+rs.xy*.5/cityScale)*ri.xy;

   float hit=0.;
   float beacon=0.;

   vec3 resultPos;

   float dist=500.;
   float face=0.;

   for(int i=0;i<150;++i){
       // 高さの計算を元に戻し、建物ごとにランダム化
       // 面の交差判定を安定させるために、1/3スケールに調整
       vec2 lo0=vec2(block+.01/cityScale);// 面の下端を調整
       vec2 loX=vec2(.3,.3)/cityScale;
       vec2 hi0=vec2(block+.69/cityScale);// 面の上端を調整
       vec2 hiX=vec2(.3,.3)/cityScale;
       float height=(.5+hash1(block))*(2.+4.*pow(noise1(.1*block),2.5))*cityHeight;
       float clampedRoad=getRoadOrCity(block,roadWidth);
       height *= clampedRoad;

       dist=500.;
       face=0.;

       // ビルの各面について交差判定を行う
       for(int j=0;j<int(float(3)*clampedRoad);++j){
       // for(int j=0;j<1;++j){
           float top=height*(1.-.1*float(j));
           vec3 lo=vec3(lo0+loX*hash2(block,float(j)),0.);
           vec3 hi=vec3(hi0+hiX*hash2(block,float(j)+.5),top);

           vec3 wall=mix(hi,lo,side);// 交差面の位置
           vec3 t=(wall-eye)*ri;

           vec3 dim=step(t.zxy,t)*step(t.yzx,t);
           float maxT=dot(dim,t);
           float maxFace=1.-dim.z;

           resultPos=eye+maxT*ray;
           if(resultPos.z<0.0){
               return CityResult(dist,beacon,face,HIT_ROAD,length(resultPos-eye),resultPos.xzy);
           }
           dim+=step(lo,resultPos)*step(resultPos,hi);// 面内判定
           if(dim.x*dim.y*dim.z>.5&&maxT<dist){
               dist=maxT;
               face=maxFace;
           }
       }

       vec2 h=hash2(block);
       if(h.x<beaconProb){
           vec3 center=vec3(block+.5/cityScale,height);
           float t=dot(center-eye,ray);
           if(t<dist){
               vec3 p=eye+t*ray;
               float fog=(exp(-p.z/fogDistance)-exp(-eye.z/fogDistance))/ray.z;
               fog=exp(fogDensity*fog);

               t=distance(center,p);
               fog*=smoothstep(1.,.5,cos(tau*(beaconFreq*time+h.y)));
               beacon+=fog*pow(clamp(1.-t*25.0,0.,1.),4.);
           }
       }

       // スタートシグナル
       if(0. < beforeProgress && startProgress < 1.){
           int index=int(passedCellNum(0.));
           TruchetData data=allSkippedData[index];
           vec2 startLine = floor(data.pos*cityScale)/cityScale;

           if(startLine.x - roadWidth + 1./cityScale < block.x
            && block.x < startLine.x + roadWidth * (beforeProgress+0.2) - 1./cityScale
            && startLine.y + 0.25 < block.y
            && block.y< startLine.y+.25+2./cityScale
            ){
               vec3 center=vec3(block+.5/cityScale,.03);
               float t=dot(center-eye,ray);
               if(t<dist){
                   vec3 p=eye+t*ray;
                   float fog=(exp(-p.z/fogDistance)-exp(-eye.z/fogDistance))/ray.z;
                   fog=exp(fogDensity*fog);
                   t=distance(center,p);
                   beacon+=fog*pow(clamp(1.-t*25.,0.,1.),4.)*10.;
               }
           }
       }

       // ゴールポイント
       int index=int(passedCellNum(RACELAP + extraMileage));
       TruchetData data=allSkippedData[int(index)];
       vec2 startLine=floor(data.pos*cityScale)/cityScale;

       if(startLine.x-roadWidth<block.x
           &&block.x<startLine.x+roadWidth
           &&block.y<startLine.y+roadWidth
           &&startLine.y-roadWidth<block.y){
           vec3 center=vec3(block+.5/cityScale,.03);
           float t=dot(center-eye,ray);
           if(t<dist){
               vec3 p=eye+t*ray;
               float fog=(exp(-p.z/fogDistance)-exp(-eye.z/fogDistance))/ray.z;
               fog=exp(fogDensity*fog);
               t=distance(center,p);
               beacon+=fog*pow(clamp(1.-t*3.,0.,1.),4.);
           }
       }

       if(dist<400.){
           return CityResult(dist,beacon,face,HIT_CITY,length(resultPos-eye),resultPos.xzy);
       }

       vec2 dim=step(dis.xy,dis.yx);
       dis+=dim*ris/cityScale;
       block+=dim*rs.xy/cityScale;
   }

   if(ray.z<0.){
       return CityResult(-eye.z*ri.z,beacon,0.,1.,1000.,(eye+1000.*ray).xzy);
   }

   return CityResult(0.,beacon,0.,NOHIT,0.,vec3(0.));
}

CityResult cityScene(vec3 ro,vec3 rd,inout vec4 returnColor){
   float dist=-(ro.y)/rd.y;// 右はri
   vec2 hit1=ro.xz+rd.xz*dist;
   // ■ シティの描画
   CityResult cityResult=cityRay(ro,rd);
   // vec3 p=ro+cityResult.distance*rd;
   vec3 p=cityResult.hitPos;

   vec2 block=floor(p.xz*cityScale)/cityScale;
   vec3 window=floor(p/windowSize);
   float x=hash1(block,window.x);
   float y=hash1(block,window.y);
   float z=hash1(block,window.z);
   vec3 color=windowColor+windowDivergence*(hash3(block)-.5);
   color*=smoothstep(.1,.9,fract(2.5*(x*y*z)));

   vec3 streetLevel=streetColor*exp(-p.y/streetDistance);
   color+=streetLevel;
   color=clamp(mix(.25*streetLevel,color,cityResult.face),0.,1.);

   float fog=(exp(-p.y/fogDistance)-exp(-ro.y/fogDistance))/rd.y;
   fog=exp(fogDensity*fog);
   color=mix(fogColor,color,fog);

   color=mix(fogColor,color,clamp(cityResult.hittedTarget,0.,1.));
   vec3 tmpBeaconColor=beaconColor;
   if(0. < startProgress && startProgress < 1.) tmpBeaconColor = beaconGreenColor;
   color+=cityResult.beacon*tmpBeaconColor;
   returnColor=vec4(color,1.);

   // ■ タイルごとのUV生成
   vec2 flooruv=floor(hit1);
   vec2 uvOfTile=hit1-flooruv-.5;
   int celltype=getcell(flooruv.xy);

   // ■ 道の描画
   // inspired by MountainBytes: PPPP 4KiB Windows mrange & virgill https://www.shadertoy.com/view/lX2GzD
   //uvから道のもとになるlenを作る
   vec2 uvOfTileForRoad=uvOfTile;
   if(celltype==0)uvOfTileForRoad*=vec2(1.,-1.);
   uvOfTileForRoad*=step(0.,uvOfTileForRoad.x+uvOfTileForRoad.y)*2.-1.;

   float len;
   float dashed;
   float dashLineSize=.1;
   float dashLineRatio=.3;
   if(celltype==2){
       len=min(abs(uvOfTileForRoad.x),abs(uvOfTileForRoad.y));
       dashed=step(fract((uvOfTileForRoad.x+uvOfTileForRoad.y)/dashLineSize),dashLineRatio);
   }else{
       len=length(uvOfTileForRoad-.5)-.5;
       float polar=atan(uvOfTileForRoad.x-.5,uvOfTileForRoad.y-.5)/(pi*2.)+.5;
       dashed=step(fract(polar/dashLineSize*4.),dashLineRatio);
   }

   //道を描画
   float roadSize=(abs(len)-roadWidth)*resolution.y*.1;
   float lineSize=.1;
   float clampedRoad=clamp(roadSize,0.,1.);
   if(cityResult.hittedTarget==HIT_ROAD){
       bool is1Load=false;

       //bpは普通の線
       //lenは点線
       float bp;
       if(is1Load){
           bp=abs(len)-.2;//1road
       }
       else{
           float centerSideLine=abs(len)-.01;
           returnColor+=vec4(roadGlow/(centerSideLine*centerSideLine)*lineSize,1.);
           bp=abs(len)-.085;//2road
           len=abs(len)-.05;//2road
       }

       vec3 glowIntensity=roadGlow/((len*len))*lineSize;
       returnColor+=vec4(glowIntensity*dashed,1.);

       float baseGlowIntensity=.25/(bp*bp)*lineSize;
       returnColor+=vec4(baseGlowIntensity*roadGlow,1.);
   }

   return cityResult;
}

Racer allRacers[RACERNUM];

struct BallResult{
   float distance;
   int racerNum;
   float distanceFromEye;
   vec3 hitPos;
};

BallResult scene(vec3 p){
   // ■ レーサーの描画
   float minD=1000.;
   int racerNum=-1;
   for(int i=0;i<RACERNUM;i++){
       float d=sdSphere(p-vec3(allRacers[i].pos.x,marbleSize,allRacers[i].pos.y),marbleSize);
       if(d<minD){
           minD=d;
           racerNum=i;
       }
   }
   return BallResult(minD,racerNum,0.,p);
}


// レイマーチングによる距離探査
BallResult rayMarch(vec3 ro, vec3 rd, inout vec3 hitPos){
   float t=0.;
   float tolerance=.001;
   // 近景
   for(int i=0;i<50;i++){
       hitPos=ro+rd*t;
       BallResult sr=scene(hitPos);
       if(sr.distance<tolerance){
           return BallResult(sr.distance,sr.racerNum,length(hitPos-ro),hitPos);
           //  vec2(t,KINKEI);// ヒット時
       }
       t+=sr.distance;
   }
   return BallResult(1000.,-1,length(hitPos-ro),hitPos);
}

BallResult ballScene(vec3 ro,vec3 rd,inout vec3 hitPos, out vec4 color){
   BallResult sr = rayMarch(ro,rd,hitPos);

   vec2 o=vec2(.001,0);
   vec3 n=normalize(vec3(
           scene(sr.hitPos+o.xyy).distance-scene(sr.hitPos-o.xyy).distance,
           scene(sr.hitPos+o.yxy).distance-scene(sr.hitPos-o.yxy).distance,
           scene(sr.hitPos+o.yyx).distance-scene(sr.hitPos-o.yyx).distance
       ));
   // balls
   float fresnel=pow(1.-dot(-rd,n),5.);
   fresnel=mix(.5,1.,fresnel);

   ro=sr.hitPos+n*.0015;
   rd=reflect(rd,n);

   CityResult bounceCr = cityScene(ro,rd,color);
   color *=fresnel;
   return sr;
}

//    ____
//   / ___|__ _ _ __ ___   ___ _ __ __ _
//  | |   / _` | '_ ` _ \ / _ \ '__/ _` |
//  | |__| (_| | | | | | |  __/ | | (_| |
//   \____\__,_|_| |_| |_|\___|_|  \__,_|
struct Camera{
   vec3 ro;
   vec3 rd;
};

vec3 createRd(in vec2 fragCoord, vec3 forward){
   vec3 right=normalize(cross(forward,vec3(0.,1.,0.)));
   vec3 up=cross(right,forward);
   vec2 xy=2.*fragCoord-resolution.xy;
   float zoom=3.;
   zoom*=resolution.y;
   vec3 rd=normalize(xy.x*-right+xy.y*up+zoom*forward);
   return rd;
}

Camera makeCamera(in vec2 fragCoord, float time, bool isStarting, vec3 hashedValue, bool isFinished){

   // ■ 画面全体のUV
   vec2 realUV=(fragCoord.xy*2.-resolution.xy)/resolution.y;

   vec3 h=hashedValue;
   bool onBoardCamera=h.x<onBoardCameraProb;
   bool backCamera=h.y<onBoardCameraProb;
   int racerNum=int(h.z*float(RACERNUM));

   // オンボードカメラ
   if(!isFinished&&!isStarting&&onBoardCamera){
       float isBack=1.;
       if(backCamera)isBack=-1.;

       vec2 center2d=allRacers[racerNum].pos;

       vec2 dirForRacingObject=allRacers[racerNum].dirForRacingObject;

       vec3 ro=vec3(center2d.x-dirForRacingObject.x*.05*isBack,.05,center2d.y-dirForRacingObject.y*.04*isBack);

       vec2 tmpUV=vec2(-realUV.x,realUV.y);
       vec3 rd=normalize(vec3(tmpUV-vec2(0.,.5),1.));
       rd.xz*=mat2(vec2(-dirForRacingObject.y,dirForRacingObject.x),dirForRacingObject)*isBack;
       return Camera(ro,rd);
   }

   vec2 center2d=allRacers[racerNum].pos;
   if(isFinished){
       int index=int(passedCellNum(RACELAP + extraMileage));
       TruchetData data=allSkippedData[index];
       center2d=data.pos;
   }

   // roの定義
   vec3 center=vec3(center2d.x,.1,center2d.y);

   vec2 m=vec2(.01*time,.5+sin(.02*time)*.2);
   // if(mouse.z>0.)m=mouse.xy/resolution.xy;
   m*=tau*vec2(1.,.25);
   float cameraDist=2.;
   vec3 mouseFix=vec3(
       cameraDist*sin(m.x)*sin(m.y),
       cameraDist*cos(m.y),
       cameraDist*cos(m.x)*sin(m.y));

   // 固定カメラ
   bool isKoteiCamera=backCamera&&!onBoardCamera;
   if(!isFinished&&!isStarting&&isKoteiCamera){
       int index=int(passedCellNum(allRacers[racerNum].mileage));
       TruchetData data=allSkippedData[index+1];
       center=vec3(data.pos.x,.1,data.pos.y);
       mouseFix=vec3(
           roadWidth*sin(m.x)*sin(m.y),
           roadWidth*cos(m.y),
           roadWidth*cos(m.x)*sin(m.y));
       vec3 ro = center+mouseFix;
       vec3 target =vec3(allRacers[racerNum].pos.x,marbleSize,allRacers[racerNum].pos.y);
       vec3 forward = normalize(target-ro);
       return Camera(ro,createRd(gl_FragCoord.xy,forward));
   }

   vec3 ro=center+mouseFix;

   if(isStarting){
       int index=int(passedCellNum(0.));
       TruchetData data=allSkippedData[index];
       center=vec3(data.pos.x,.0,data.pos.y);
       ro = center + vec3(data.dir.x,0.3,data.dir.y) + mouseFix*0.05;
   }

   // rdの定義
   vec3 forward=normalize(center-ro);
   vec3 rd=createRd(gl_FragCoord.xy,forward);

   return Camera(ro,rd);
}

//   __  __    _    ___ _   _
//  |  \/  |  / \  |_ _| \ | |
//  | |\/| | / _ \  | ||  \| |
//  | |  | |/ ___ \ | || |\  |
//  |_|  |_/_/   \_\___|_| \_|
void main()
{
   vec2 floorpos=STARTPOSITION;
   vec2 initialPos=INITIALPOS;
   vec2 dir=INITIALDIR;// 初期の方向 以降最初はx=1の方向に進む前提のコード

   // ■ 時間の設定
   float gameSpeed = time * 0.75;
   float time = fract(gameSpeed / (ALLLAP)) * (ALLLAP);
   float raceTime = BEFORELAP < time ? time - BEFORELAP: 0.;
   progress = raceTime / RACELAP;
   beforeProgress = clamp(time/(BEFORELAP),0.,1.);
   startProgress = clamp((raceTime/STARTLAP),0.,1.);
   finishProgress = clamp((time-(ALLLAP-AFTERLAP-ENDLAP))/AFTERLAP,0.,1.);
   // ■ トルシェのデータの生成
   setSkipTruchetData(initialPos,dir,floorpos,time);


   // ■ レーサーの生成
   for(int i=0;i<RACERNUM;i++){
       float noiseVert=snoise(vec2(time*.01+COURCEID,float(i+1)*100.))*3.*progress-2.;
       float noiseSide=snoise(vec2(time*.1+COURCEID,float(i+1)*10.*COURCEID))*.25;
       float normalMileage = raceTime + noiseVert + extraMileage;
       normalMileage = min(normalMileage, floor(RACELAP + extraMileage));
       float normalSidePosition = noiseSide;

       float beforeMileage = float(i) / float(RACERNUM) * 0.25;
       float beforeSidePosition = (i % 2 == 0) ? 0.2 : -0.2;

       // スタート時に徐々にスタート
       float mileage = mix(beforeMileage, normalMileage, startProgress);
       float sidePosition = mix(beforeSidePosition, normalSidePosition, startProgress);

       allRacers[i]=createRacerFromTruchet(mileage,sidePosition,RACERNUMCOLOR[i],54321.);
   }
   bubbleSort(allRacers,RACERNUM);

   // ランダム値
   vec3 h=hash3(floor(vec2(time/3.))+COURCEID);
   int racerNum=int(h.z*float(RACERNUM));

   // ■ カメラの生成
   Camera camera = makeCamera(gl_FragCoord.xy, raceTime, startProgress*2.<1., h, 0.<finishProgress);
   vec3 ro=camera.ro;
   vec3 rd=camera.rd;

   // ■ レイキャスティング
   float dist=-(ro.y)/rd.y; // 右はri
   vec2 hit1=ro.xz+rd.xz*dist;

   //       _             _   ____                     _
   //   ___| |_ __ _ _ __| |_|  _ \ _ __ __ ___      _(_)_ __   __ _
   //  / __| __/ _` | '__| __| | | | '__/ _` \ \ /\ / / | '_ \ / _` |
   //  \__ \ || (_| | |  | |_| |_| | | | (_| |\ V  V /| | | | | (_| |
   //  |___/\__\__,_|_|   \__|____/|_|  \__,_| \_/\_/ |_|_| |_|\__, |
   //                                                          |___/
   // 空の描画
   outColor=vec4(fogColor,1);

   // ■ シティの描画
   CityResult cityResult = cityScene(ro,rd,outColor);

   // ■ レーサーの描画
   vec3 hitPos;
   vec4 bounceColor;
   BallResult sr=ballScene(ro,rd,hitPos,bounceColor);
   if(sr.racerNum!=-1&&sr.distanceFromEye<cityResult.distanceFromEye){
       outColor=mix(bounceColor*3.,allRacers[sr.racerNum].color,.4);
       // outColor=allRacers[sr.racerNum].color;
   }

   //       _      _
   //    __| | ___| |__  _   _  __ _
   //   / _` |/ _ \ '_ \| | | |/ _` |
   //  | (_| |  __/ |_) | |_| | (_| |
   //   \__,_|\___|_.__/ \__,_|\__, |
   //                          |___/
   // ■グリッドの描画
   float grid=calculateGridLine(hit1,1.,.02);
   if(ONGRID) outColor=mix(outColor,vec4(0., 0.0, 1.0, 1.0),grid);


   //                       _
   //    _____   _____ _ __| | __ _ _   _
   //   / _ \ \ / / _ \ '__| |/ _` | | | |
   //  | (_) \ V /  __/ |  | | (_| | |_| |
   //   \___/ \_/ \___|_|  |_|\__,_|\__, |
   //                               |___/
   // ■ 画面UVの作成
   vec2 uvForScreen=gl_FragCoord.xy/resolution.x;

   // ■ mapの描画
   if(.75<uvForScreen.x && .25<uvForScreen.y){
       vec2 baseUV = (gl_FragCoord.xy*2.-resolution.xy+vec2(-.75,-.25)*resolution.xy)/resolution.x;
       vec2 gameUV=8.*baseUV+allRacers[racerNum].pos;//3dでは不要
       float mapRoadWidth=.15;
       float mapClampedRoad = getRoadOrCity(gameUV,mapRoadWidth);

       vec4 roadColor = vec4(0);
       vec4 cityColor = vec4(1);

       // スタート地点
       if(floor(gameUV)==allSkippedData[0].floorpos){
         cityColor = (0. < startProgress) ? vec4(0.,1.,0.,1.):vec4(1.,0.,0.,1.);
       }

       // ゴール地点
       TruchetData data=allSkippedData[int(RACELAP)];
       if(floor(gameUV)==floor(data.floorpos)){
           cityColor = vec4(1.,0.,0.,1.);
       }
       outColor=mix(roadColor,cityColor,mapClampedRoad);
       for(int i=RACERNUM-1;0<=i;i--){
           if(drawCircle(gameUV,allRacers[i].pos)){
                   outColor=allRacers[i].color;
           }
       }
   }

   // ■ 順位の描画
   if(uvForScreen.x<0.15){
       uvForScreen*=40.;
       int lineNum=int(floor((uvForScreen.y)/1.2));

       ivec2 index=ivec2(uvForScreen/vec2(.8,1.2));
       uvForScreen.x=mod(uvForScreen.x,.8);
       uvForScreen.y=mod(uvForScreen.y,1.2);
       int max_char = 1;
       int raceOrderInIndex=15-lineNum;
       if(0 <= raceOrderInIndex && raceOrderInIndex <= RACERNUM){
             // 順序
           if(0==index.x)outColor=vec4(font(uvForScreen,raceOrderInIndex+1),1.);

           // 色
           if(1 == index.x){
               outColor=allRacers[raceOrderInIndex-1].color;
           }
           // Interval表示
           // 先頭
           if(raceOrderInIndex == 1){
               if(2==index.x)outColor=vec4(0.,0.,0.,1.);
               if(3==index.x)outColor=vec4(0.,0.,0.,1.);
               if(4==index.x)outColor=vec4(font(uvForScreen,45),1.);
               if(5==index.x)outColor=vec4(font(uvForScreen,50),1.);
               if(6==index.x)outColor=vec4(font(uvForScreen,56),1.);
           }
           else{ // 先頭以外
               float interval = allRacers[raceOrderInIndex-2].mileage - allRacers[raceOrderInIndex-1].mileage;
               if(2==index.x)outColor=vec4(font(uvForScreen,73),1.);
               if(3==index.x)outColor=vec4(font(uvForScreen,int(interval+1.)),1.);
               if(4==index.x)outColor=vec4(font(uvForScreen,76),1.);
               if(5==index.x)outColor=vec4(font(uvForScreen,int(fract(interval)*10.+1.)),1.);
               if(6==index.x)outColor=vec4(font(uvForScreen,int(fract(interval*10.)*10.+1.)),1.);
           }

           //選択中のレーサーの色を反転
           if(raceOrderInIndex-1 == racerNum && 2 <= index.x && index.x <= 6){
               outColor=1.0-outColor;
           }

           // ラップ数表示
           if(raceOrderInIndex==0){
               raceTime=min(raceTime+extraMileage,RACELAP);
               int lap10=int(fract(raceTime*.01)*10.);
               int lap1=int(fract(raceTime*.1)*10.);
               if(0==index.x)outColor=vec4(0.,0.,0.,1.);
               if(1==index.x)outColor=vec4(font(uvForScreen,lap10+1),1.);
               if(2==index.x)outColor=vec4(font(uvForScreen,lap1+1),1.);
               if(3==index.x)outColor=vec4(font(uvForScreen,77),1.);
               int niketame=int(fract(RACELAP*.01)*10.);
               int hitoketame=int(fract(RACELAP*.1)*10.);
               if(4==index.x)outColor=vec4(font(uvForScreen,niketame+1),1.);
               if(5==index.x)outColor=vec4(font(uvForScreen,hitoketame+1),1.);
               if(6==index.x)outColor=vec4(0.,0.,0.,1.);
           }
       }
   }

   // 終了後暗転
   if(0.<finishProgress){
       outColor=mix(clamp(outColor,0.,1.),vec4(0.),finishProgress);
       return;
   }
}