// Felipe Marinho Tavares
// R.A.: 265680
// Unicamp - MC937A/MO603A – Computação Gráfica - 2020-S2 - Jorge Stolfi

// ======================================================================
// CORES E TEXTURAS

background{ color rgb < 0.75, 0.80, 0.85 > }

#declare brown_soft_149_111_82 = color rgb < 149/255, 111/255, 82/255 >;

#declare tx_woodish =
  texture{
    pigment{ brown_soft_149_111_82 }
    finish{ diffuse 0.8 ambient 0.1 specular 0.5 roughness 0.005 }
  }

#declare tx_redish =
  texture{
    pigment{ color rgb < 255/255, 0/255, 0/255 > }
    finish{ diffuse 0.8 ambient 0.1 specular 0.5 roughness 0.005 }
  }

#declare tx_gray70 = 
  texture{
    pigment{ color rgb <179/255, 179/255, 179/255> }
  }

#declare tx_gray85 = 
  texture{
    pigment{ color rgb <217/255, 217/255, 217/255> }
  }

#declare tx_gray90 = 
  texture{
    pigment{ color rgb <230/255, 230/255, 230/255> }
  }

#declare tx_rubi =
  texture{
    pigment{ color rgb < 1.000, 0.000, 0.500 > filter 0.995 }
    finish{ diffuse 0.01 ambient 0.02
    reflection 0.15 specular 0.35 roughness 0.005 }
  }

#declare tx_package =
  texture{
    pigment{ color rgb < 0.900, 0.900, 0.950 > filter 0.995 }
    finish{ diffuse 0.01 ambient 0.02
    reflection 0.05 specular 0.35 roughness 0.005 }
  }

#declare tx_fixa = 
  texture{
    pigment{ color rgb < 0.000, 0.800, 0.100 > }
    finish{ diffuse 0.0 ambient 1.0 }
  }

#declare tx_xadrez =
  texture{
    pigment{ checker color rgb < 0.600, 0.600, 0.600 >, color rgb < 0.900, 0.900, 0.900 > }
    finish{ diffuse 0.9 ambient 0.1 }
    scale 0.95
  }

// ======================================================================
// DESCRI��O DA CENA 

#macro interpola1(tt, tt0, tt1, vv0, vv1)
  #local rr = (tt - tt0) / (tt1 - tt0);
  #local vv = (1 - rr) * vv0 + rr * vv1;
  vv
#end

#macro interpola3(tt, tt0, tt3, vv0, vv1, vv2, vv3)
  #local vv01   = interpola1(tt, tt0, tt3,  vv0,   vv1);
  #local vv12   = interpola1(tt, tt0, tt3,  vv1,   vv2);
  #local vv23   = interpola1(tt, tt0, tt3,  vv2,   vv3);
  #local vv012  = interpola1(tt, tt0, tt3, vv01,  vv12);
  #local vv123  = interpola1(tt, tt0, tt3, vv12,  vv23);
  #local vv0123 = interpola1(tt, tt0, tt3, vv012, vv123);
  vv0123
#end

#macro segmento(N, P0, P1, P2, P3, R0, R3)
  #local iter = 0;
  union{
    #while(iter < N)
      #local tt = iter / (N-1);
      #local pp = interpola3(tt, 0, 1, P0, P1, P2, P3);
      #local rr  = interpola1(tt, 0, 1, R0, R3);
      sphere{pp,
             rr
             texture{tx_gray85} }
      #local iter = iter + 1;
    #end
  }
#end

#macro tentaculo(N, A0, A1, A2, B1, B2, C1, C2, C3, RA0, RC3)
  union{
    #local A3 = (A2 + B1) / 2;
    #local B0 = A3;
    #local B3 = (B2 + C1) / 2;
    #local C0 = B3;
    #local RA3 = interpola1(1/3, 0, 1, RA0, RC3);
    #local RB0 = RA3;
    #local RB3 = interpola1(2/3, 0, 1, RA0, RC3);
    #local RC0 = RB3;
    segmento(N, A0, A1, A2, A3, RA0, RA3)
    segmento(N, B0, B1, B2, B3, RB0, RB3)
    segmento(N, C0, C1, C2, C3, RC0, RC3)
  }
#end

#macro tentaculo_aleatorio(N, smt, A0, C3, RA0, RC3)
  #local roll = seed(smt);
  #local len = vlength(C3 - A0);
  #local ps = len/1.5; // pertubation scaler

  #local pert = <(rand(roll)-0.5)*ps, (rand(roll)-0.5)*ps, (rand(roll)-0.5)*ps>;
  #local A1 = interpola1(1/9, 0, 1, A0, C3) + pert;
  
  #local pert = <(rand(roll)-0.5)*ps, (rand(roll)-0.5)*ps, (rand(roll)-0.5)*ps>;
  #local A2 = interpola1(2/9, 0, 1, A0, C3) + pert;
  
  #local pert = <(rand(roll)-0.5)*ps, (rand(roll)-0.5)*ps, (rand(roll)-0.5)*ps>;
  #local B1 = interpola1(4/9, 0, 1, A0, C3) + pert;
  
  #local pert = <(rand(roll)-0.5)*ps, (rand(roll)-0.5)*ps, (rand(roll)-0.5)*ps>;
  #local A3 = ((A2 + B1) / 2) + pert;
  #local B0 = A3;
  
  #local pert = <(rand(roll)-0.5)*ps, (rand(roll)-0.5)*ps, (rand(roll)-0.5)*ps>;
  #local B2 = interpola1(5/9, 0, 1, A0, C3) + pert;
  
  #local pert = <(rand(roll)-0.5)*ps, (rand(roll)-0.5)*ps, (rand(roll)-0.5)*ps>;
  #local C1 = interpola1(7/9, 0, 1, A0, C3) + pert;
  
  #local pert = <(rand(roll)-0.5)*ps, (rand(roll)-0.5)*ps, (rand(roll)-0.5)*ps>;
  #local B3 = ((B2 + C1) / 2) + pert;
  #local C0 = B3;

  #local pert = <(rand(roll)-0.5)*ps, (rand(roll)-0.5)*ps, (rand(roll)-0.5)*ps>;
  #local C2 = interpola1(8/9, 0, 1, A0, C3) + pert;
  
  tentaculo(N, A0, A1, A2, B1, B2, C1, C2, C3, RA0, RC3)
#end

#macro virus()
  union{
    sphere{<0,0,0>,
           2
           texture{tx_gray85} }
    tentaculo_aleatorio(100, 8629, <0,2,0>, <0,4,0>, 0.5, 0.01)
    tentaculo_aleatorio(100, 9011,
                       <0, 2*cos(45),   2*sin(45)>, 
                       <0, 2*cos(45)+4, 2*sin(45)+2>, 0.5, 0.01)
    tentaculo_aleatorio(100, 9283,
                       <0, -2*cos(45),   2*sin(45)>, 
                       <0, -2*cos(45)+1, 2*sin(45)+3>, 0.5, 0.01)
    tentaculo_aleatorio(100, 9479, <0, -2, 0>, <0, -4, 1>, 0.5, 0.01)
    tentaculo_aleatorio(100, 9533,
                       <0,  2*cos(45),  -2*sin(45)>,
                       <-1, 2*cos(45)+2,-2*sin(45)-4>, 0.5, 0.01)
    tentaculo_aleatorio(100, 9721,
                       <0, -2*cos(45),   -2*sin(45)>,
                       <5, -2*cos(45)-1, -2*sin(-45)-4>, 0.5, 0.01)
  }
#end

#macro interpola3H(tt, t0, t1, p0, d0, d1, p1) // interpol hermite
  #local rr = (tt - t0)/(t1 - t0);
  #local ss = 1 - rr;
  #local ph0 = rr*rr*(2*rr - 3) + 1;
  #local dh0 = + rr*ss*ss * (t1 - t0);
  #local dh1 = - ss*rr*rr * (t1 - t0);
  #local ph1 = ss*ss*(2*ss - 3) + 1;
  #local pp = ph0*p0 + dh0*d0 + dh1*d1 + ph1*p1;
  pp
#end

#macro tentaculo_hermite(N, tt, t0, t1, A0, A1H, A2H, B1H, B2H, C1H, C2H, C3H, RA0, RC3)
  union{
    #local A1 = interpola3H(tt, t0, t1, A1H[0], A1H[1], A1H[2], A1H[3]);
    #local A2 = interpola3H(tt, t0, t1, A2H[0], A2H[1], A2H[2], A2H[3]);
    #local B1 = interpola3H(tt, t0, t1, B1H[0], B1H[1], B1H[2], B1H[3]);
    #local B2 = interpola3H(tt, t0, t1, B2H[0], B2H[1], B2H[2], B2H[3]);
    #local C1 = interpola3H(tt, t0, t1, C1H[0], C1H[1], C1H[2], C1H[3]);
    #local C2 = interpola3H(tt, t0, t1, C2H[0], C2H[1], C2H[2], C2H[3]);
    #local C3 = interpola3H(tt, t0, t1, C3H[0], C3H[1], C3H[2], C3H[3]);
    tentaculo(N, A0, A1, A2, B1, B2, C1, C2, C3, RA0, RC3)
  }
#end

#macro parado(P)
  #local PH = array[4];
  #local PH[0] = P;
  #local PH[1] = < 0, 0, 0 >;
  #local PH[2] = < 0, 0, 0 >;
  #local PH[3] = P;
  PH
#end

#macro tentaculo_hermite_teste(tt)
  #local N = 100;
  #local A0 = < 0, 0, 0 >;
  #local A1H = parado(< 1, 0, 0 >);
  #local A2H = parado(< 2, 0, 0 >);
  #local B1H = parado(< 4, 0, 0 >);
  #local B2H = parado(< 5, 0, 0 >);
  #local C1H = parado(< 7, 0, 0 >);
  #local C2H = parado(< 8, 0, 0 >);
  #local C3H = array[4];
  #local C3H[0] = < 9, 0, -1 >;
  #local C3H[1] = < 0, +1, 0 >;
  #local C3H[2] = < 0, -1, 0 >;
  #local C3H[3] = < 9, 0, +1 >;
  #local RA0 = 0.2;
  #local RC3 = 0.02;
  object{ tentaculo_hermite(N, tt, 0, 1, A0, A1H, A2H, B1H, B2H, C1H, C2H, C3H, RA0, RC3) }
#end

#macro encontra_intervalo(tt, NQ, TQ)
  #local k0 = 0; // Por via das duvidas.
  #local kq = 0;
  #while (kq < NQ)
    #if ((TQ[kq] <= tt) & (tt <= TQ[kq+1]))
      #local k0 = kq;
    #end
    #local kq = kq + 1;
  #end
  k0
#end

#macro tentaculo_anim(N, tt, A0, NQ, TQ,
                      PA1, DA1, PA2, DA2,
                      PB1, DB1, PB2, DB2,
                      PC1, DC1, PC2, DC2,
                      PC3, DC3, RA0, RC3)
  // Determina os quadros chave a interpolar k0,k1 e os tempos t0,t1:
  #local k0 = encontra_intervalo(tt, NQ, TQ);
  #local k1 = mod(k0 + 1, NQ);
  #local t0 = TQ[k0];
  #local t1 = TQ[k0 + 1];

  // Pega posicoes e velocidades nesses dois quadros chave:
  #local A1H = array[4];
  #local A1H[0] = PA1[k0];
  #local A1H[1] = DA1[k0];
  #local A1H[2] = DA1[k1];
  #local A1H[3] = PA1[k1];

  #local A2H = array[4];
  #local A2H[0] = PA2[k0];
  #local A2H[1] = DA2[k0];
  #local A2H[2] = DA2[k1];
  #local A2H[3] = PA2[k1];

  #local B1H = array[4];
  #local B1H[0] = PB1[k0];
  #local B1H[1] = DB1[k0];
  #local B1H[2] = DB1[k1];
  #local B1H[3] = PB1[k1];

  #local B2H = array[4];
  #local B2H[0] = PB2[k0];
  #local B2H[1] = DB2[k0];
  #local B2H[2] = DB2[k1];
  #local B2H[3] = PB2[k1];

  #local C1H = array[4];
  #local C1H[0] = PC1[k0];
  #local C1H[1] = DC1[k0];
  #local C1H[2] = DC1[k1];
  #local C1H[3] = PC1[k1];

  #local C2H = array[4];
  #local C2H[0] = PC2[k0];
  #local C2H[1] = DC2[k0];
  #local C2H[2] = DC2[k1];
  #local C2H[3] = PC2[k1];

  #local C3H = array[4];
  #local C3H[0] = PC3[k0];
  #local C3H[1] = DC3[k0];
  #local C3H[2] = DC3[k1];
  #local C3H[3] = PC3[k1];
  // Gera o tentaculo entre esses dois quadros chave:
  object{ tentaculo_hermite(N, tt, t0, t1, A0, A1H, A2H, B1H, B2H, C1H, C2H, C3H, RA0, RC3) }
#end

#macro ranvec(sem)
  #local vv = < 2*rand(sem)-1, 2*rand(sem)-1, 2*rand(sem)-1 >;
  vv
#end

#macro tentaculo_aleatorio_anim(N, tt, it, A0, Z3, RA0, RC3)
  // it: num of the tentacle
  #local smt = seed(4615 + 417*it); // Semente para este tentaculo.
  #local NQ = 3; // Quadros-chave excluindo final (= inicial).
  #local TQ = array[NQ+1]; // Tempos dos quadros-chave
  #local TQ[0] = 0.0000; // Inicio da animacao.
  #local TQ[1] = 0.3333; // Fim do primeiro movimento.
  #local TQ[2] = 0.6667; // Fim do segundo movimento.
  #local TQ[3] = 1.0000; // Fim da animacao.
  // Gera posicoes e velocidades aleatorias do tentaculo para quadros-chave
  #local mP = 0.5*vlength(Z3 - A0); // Max perturbacao do ponto.
  #local mV = 4.0*vlength(Z3 - A0); // Max velocidade.
  #local PA1 = array[NQ]; #local DA1 = array[NQ];
  #local PA2 = array[NQ]; #local DA2 = array[NQ];
  #local PB1 = array[NQ]; #local DB1 = array[NQ];
  #local PB2 = array[NQ]; #local DB2 = array[NQ];
  #local PC1 = array[NQ]; #local DC1 = array[NQ];
  #local PC2 = array[NQ]; #local DC2 = array[NQ];
  #local PC3 = array[NQ]; #local DC3 = array[NQ];
  #local kq = 0;
  #while (kq < NQ)
    #local PA1[kq] = interpola1(1/9, 0,1, A0,Z3) + (1/9)*mP*ranvec(smt);
    #local DA1[kq] = (1/9)*mV*ranvec(smt);
    #local PA2[kq] = interpola1(2/9, 0,1, A0,Z3) + (2/9)*mP*ranvec(smt);
    #local DA2[kq] = (2/9)*mV*ranvec(smt);

    #local PB1[kq] = interpola1(4/9, 0,1, A0,Z3) + (4/9)*mP*ranvec(smt);
    #local DB1[kq] = (4/9)*mV*ranvec(smt);
    #local PB2[kq] = interpola1(5/9, 0,1, A0,Z3) + (5/9)*mP*ranvec(smt);
    #local DB2[kq] = (5/9)*mV*ranvec(smt);

    #local PC1[kq] = interpola1(7/9, 0,1, A0,Z3) + (7/9)*mP*ranvec(smt);
    #local DC1[kq] = (7/9)*mV*ranvec(smt);
    #local PC2[kq] = interpola1(8/9, 0,1, A0,Z3) + (8/9)*mP*ranvec(smt);
    #local DC2[kq] = (8/9)*mV*ranvec(smt);
    #local PC3[kq] = Z3 + mP*ranvec(smt);
    #local DC3[kq] = mV*ranvec(smt);
    #local kq = kq + 1;
  #end
  object{ tentaculo_anim(N, tt, A0, NQ, TQ,
                         PA1, DA1, PA2, DA2,
                         PB1, DB1, PB2, DB2,
                         PC1, DC1, PC2, DC2,
                         PC3, DC3, RA0, RC3) }
#end

#macro virus_anim(tt)
  union{
    sphere{<0,0,0>,
           2
           texture{tx_gray85} }

    #local N = 300;
    tentaculo_aleatorio_anim(N, tt, 1, <0,2,0>, <0,4,0>, 0.5, 0.01)
    tentaculo_aleatorio_anim(N, tt, 2,
                             <0, 2*cos(45),   2*sin(45)>, 
                             <0, 2*cos(45)+4, 2*sin(45)+2>, 0.5, 0.01)
    tentaculo_aleatorio_anim(N, tt, 3,
                             <0, -2*cos(45),   2*sin(45)>, 
                             <0, -2*cos(45)+1, 2*sin(45)+3>, 0.5, 0.01)
    tentaculo_aleatorio_anim(N, tt, 4,
                             <0, -2, 0>, <0, -4, 1>, 0.5, 0.01)
    tentaculo_aleatorio_anim(N, tt, 5,
                             <0,  2*cos(45),   -2*sin(45)>,
                             <-1, 2*cos(45)+2, -2*sin(45)-4>, 0.5, 0.01)
    tentaculo_aleatorio_anim(N, tt, 6,
                             <0, -2*cos(45),   -2*sin(45)>,
                             <5, -2*cos(45)-1, -2*sin(-45)-4>, 0.5, 0.01)
  }
#end

#macro package()
  union{
    difference{
      object { box{ <-7.01,-7.01,-7.01>, <+7.01,+7.01,+7.01> texture { tx_package }} }
      object { box{ <-7,-7,-7>, <+7,+7,+7> texture { tx_package }} }
    }
  }
#end

// ---

// Aqui est� a cena, finalmente:

#include "eixos.inc"
#include "camlight.inc"
#include "frontal.inc" // frontal translates and rotates the obj to infront of camera and light source
#declare centro_cena = < 0.00, 0.00, 0.00 >;
#declare raio_cena = 20.0;
#declare dir_camera = < 25.00, 8.00, 12.00 >;
#declare dist_camera = 5*raio_cena;
#declare intens_luz = 1.20;
camlight(centro_cena, raio_cena, dir_camera, dist_camera , z, intens_luz)

union{
  //object{ eixos(20.00) translate <0, 0, 0> }

  //object{ virus() }

  object { box {<-80, -80, -7.02>, <80, 80, -7.02> texture{tx_xadrez}} } // background
  object { package() }
  object { virus_anim(clock) scale 0.95}

  #local obj =
  union{
    object {
      text{
        ttf "ttf/arial.ttf"
        "Practice Social"
        0.25, 0
        texture{ tx_fixa }
      }
      rotate 90*y
      rotate 90*x
      translate <1, -3, -3>
    }
    object {
      text{
        ttf "ttf/arial.ttf"
        "Distancing"
        0.25, 0
        texture{ tx_fixa }
      }
      rotate 90*y
      rotate 90*x
      translate <1, -2.25, -4>
    }
  };

  #declare dist_overlay = 0.60 * dist_camera;
  object{ frontal(obj, centro_cena, dir_camera, dist_overlay, z) }
}