/*
   XBlast Robot File

   (C) by Mark Weyer
*/



/*
   Parameters
   ==========

   Copied from the official parameters
   -----------------------------------

   Eye_colour		- colour of light in eyes and rear
   Chitin_texture	- used for head and rear
   Hair_texture_x with x in {lr,Lr,lR,LR}
			- used for the torso (which consists of hairs only)
			  change in case of l indicates change of ring
			  (or shift in direction of _l_ength)
			  change in case of r indicates change of spiral
			  (or shift in direction of _r_ing)

   Determined via frames
   ---------------------

   Torso_wave (on/off)	- on: Torso is shaped like a wave
			  off: Torso is shaped bent
   Torso_phase (0-2)	- Torso_wave = on:
			  the wave shape and hair pattern shift with this phase
   Torso_bend_deg (0.1-179.9)
			- Torso_wave = off:
			  the angle that the torso describes
   Eye_sharpness (0-4)	- 0 gives completely blunt eyes
                          (constant media density)
                          positive value give eyes which are brighter
                          in the middle. The value is the exponent of density
                          increase with proximity to the center.
   Hair_wind_bend_deg (0.1-179.9)
			- the angle that hairs are bent

   Calculated from the above
   -------------------------

   Neck_ang_deg (0-90)	- the angle the head is bowed.
			  180-(angle between neck and nose)
   Rear_bend_deg (0.1-179.9)
			- the angle that the rear is bent
   Antenna_bend_deg (0.1-179.9)
			- determines the angle that the antennae are bent
   Torso_y, Torso_z	- curve torso describes (parameterized from 0 to 1)
   Torso_dy, Torso_dy	- derivative of Torso_y, Torso_z
*/

#local outer_version = version;
#version 3.5;

//
// Colours and textures
//

#macro Colour_2_Texture(C)
  texture {pigment {color C} finish {specular 0.5 ambient 0.2}}
#end

#local Eye_colour = faceColor;
#local Chitin_texture = Colour_2_Texture(helmetColor)
#local Hair_texture_lr = Colour_2_Texture(bodyColor)
#local Hair_texture_Lr = Colour_2_Texture(backpackColor)
#local Hair_texture_lR = Colour_2_Texture(armsLegsColor)
#local Hair_texture_LR = Colour_2_Texture(handsFeetColor)


//
// frame initialization
//

#local Torso_phase = 0;
#local Torso_bend_deg = 1;

#if (playerWinning)
  #local Torso_wave = off;
  #local Torso_bend_deg = 30+playerWinningTime*30;
  #local Eye_sharpness = (12-playerWinningTime*4)/3;
  #local Hair_wind_bend_deg = 15+playerWinningTime*30;
#end

#if (playerLosing)
  #local Torso_wave = off;
  #local Torso_bend_deg = 90+playerLosingTime*30;
  #local Eye_sharpness = (4-playerLosingTime*4)/3;
  #local Hair_wind_bend_deg = 90+playerLosingTime*60;
#end

#if (playerKilled)
  #local Torso_wave = off;
  #local Torso_bend_deg = 179;
  #local Eye_sharpness = 0;
  #local Hair_wind_bend_deg = 10;
#end

#if (playerWalking)
  #local Torso_wave = on;
  #local Torso_phase = playerWalkingTime*2;
  #local Eye_sharpness = 3;
  #local Hair_wind_bend_deg = 90;
#end

#if (playerStanding)
  #local Torso_wave = off;
  #local Torso_bend_deg = 60;
  #local Eye_sharpness = 2;
  #local Hair_wind_bend_deg = 60;
#end


//
// internal constants
//

#local Torso_length = 2;
#local Torso_bend_center_T = 1/2;
#local Torso_bend_rad1 = Torso_bend_deg*pi/180;			// radians
#local Torso_bend_rad2 = Torso_length/Torso_bend_rad1;		// radius
#local Torso_bend_center_deg = 60;
#local Torso_bend_center_rad = Torso_bend_center_deg*pi/180;
#local Torso_w_min = 1/12;
#local Torso_w_max = 1/2;
#local Torso_w = function(T)
  {(sin((T)*pi)*(Torso_w_max-Torso_w_min)+Torso_w_min)}
#local Torso_dw = function(T) {(cos((T)*pi)*pi*(Torso_w_max-Torso_w_min))}
#local Torso_wave_amp = 1/3;
#if (Torso_wave)
  #local Neck_ang_deg = 30;
  #local Rear_bend_deg = 30;
  #local Antenna_bend_deg = 120;
  #local Eye_sharpness = 3;
  #local Torso_y = function(T) {(sin(((T)-Torso_phase)*pi)*Torso_wave_amp+2)}
  #local Torso_z = function(T) {(Torso_length*((T)-1/2)+1/3)}
  #local Torso_dy = function(T) {(cos(((T)-Torso_phase)*pi)*pi*Torso_wave_amp)}
  #local Torso_dz = function(T) {(Torso_length)}
#else
  #local Neck_ang_deg = Torso_bend_deg/2;
  #local Rear_bend_deg = Torso_bend_deg/2;
  #local Antenna_bend_deg = Torso_bend_deg;
  #local Eye_sharpness = 2;
  #local Torso_y = function(T)
    {((cos(((T)-Torso_bend_center_T)*Torso_bend_rad1+Torso_bend_center_rad)
        -cos(Torso_bend_center_rad))
      *Torso_bend_rad2+2)}
  #local Torso_z = function(T)
    {((sin(((T)-Torso_bend_center_T)*Torso_bend_rad1+Torso_bend_center_rad)
        -sin(Torso_bend_center_rad))
      *Torso_bend_rad2+1/3)}
  #local Torso_dy = function(T)
    {(-sin(((T)-Torso_bend_center_T)*Torso_bend_rad1+Torso_bend_center_rad)
      *Torso_bend_rad2*Torso_bend_rad1)}
  #local Torso_dz = function(T)
    {(cos(((T)-Torso_bend_center_T)*Torso_bend_rad1+Torso_bend_center_rad)
      *Torso_bend_rad2*Torso_bend_rad1)}
#end


#local atanf=function(b,a)				// b=sin, a=cos
  {(select((b),
    select((a),
      select((a)-(b),
        atan2(-(b),-(a))-pi,
        -pi/2-atan2(-(a),-(b))),
      select((a)+(b),
        atan2((a),-(b))-pi/2,
        -atan2(-(b),(a)))),
    select((a),
      select((a)+(b),
        pi-atan2((b),-(a)),
        pi/2+atan2(-(a),(b))),
      select((a)-(b),
        pi/2-atan2((a),(b)),
        atan2((b),(a)))
      )))}



#local pre_mix = function(x) {select(x,0,0,exp(-1/x))}
#local mix = function(x1,x2,y1,y2,x)
  {(y2*pre_mix((x-x1)/(x2-x1))+y1*pre_mix((x2-x)/(x2-x1))) /
    (pre_mix((x-x1)/(x2-x1))+pre_mix((x2-x)/(x2-x1)))}
#local End = function(z1,z2,z)
  {mix(z1,z2,pow((z-z2)/(z2-z1),2),0,z)}
#local outer =
  function(zs1,zs2,zv1,zv2,zh1,zh2,ze1,ze2,w1,h1,y1,w2,h2,y2,x,y,z)
  {End(zs1,zs2,z)+
    End(-ze2,-ze1,-z)+
    pow(x/mix(zh1,zh2,w1,w2,z),4)+
      pow((y-mix(zv1,zv2,y1,y2,z))/mix(zv1,zv2,h1,h2,z),4)
  }
#local round_bar = function(Angle,r1,r2,x,y,z)
  {pow(x/r2,2)+
    pow((sqrt(pow(y,2)+pow(z,2))-r1)/r2,2)+
    pow(mix(-r2,0,pow(y/r2,2),(atanf(y,z))/Angle,y),2)}

#local mix_eps_main = 0.5;
#local mix_eps_eyes = 0.5;
#local mix_eps_neck = 0.5;
#local mix_eps_antenna = 0.5;

#local Head_length = 3;
#local Head_width = 3;
#local Head_height = 3;
#local Head_scale = 1/4;

#local Eye_x = Head_width*0.4;
#local Eye_y = Head_height/3;
#local Eye_z = -Head_length/4;
#local Eye_rad = Head_width/4;
#local Eye_ball_depth = Eye_rad/3;
#local Eye_ball_rad = Eye_rad*2/3;
#local Eye_brightness = 1/3;
#local Eye_greyness = 1/20;
#if (playerKilled)
  #local Eye_greyed_colour = 0;
#else
  #local Eye_greyed_colour = Eye_colour*(1-Eye_greyness)+<1,1,1>*Eye_greyness;
#end
#local Eye_fac =
  (Eye_sharpness+1)*(Eye_sharpness+2)*(Eye_sharpness+3)/
  (Eye_ball_rad*Head_scale);
#local Eye_density = function(x,y,z)
  {pow(1-sqrt(pow(x,2)+pow(y,2)+pow(z,2)),Eye_sharpness)}
#local Eye_samples = 3+int(pow(10,Eye_sharpness));

#local eye =
  sphere {
    0 1
    hollow
    texture {pigment {transmit 1}}
    interior {
      media {
        emission Eye_greyed_colour*Eye_brightness*Eye_fac
        density {function {Eye_density(x,y,z)}}
        intervals 1
        method 3
        samples Eye_samples,Eye_samples
      }
    }
    scale Eye_ball_rad
    translate <Eye_x,Eye_y,Eye_z>+<-1,-1,1>*Eye_ball_depth/sqrt(3)
  }

#local Nose_length = 3.5;
#local Nose_tip_length = 1/4;
#local Nose_width = 1/3;
#local Nose_height = 1/3;

#local Neck_length = 3;
#local Neck_hlen = Neck_length/2;
#local Neck_rad = Head_width/6;
#local Neck_ang_rad = Neck_ang_deg*pi/180;

#local Antenna_length = 4;
#local Antenna_rad = 1/8;
#local Antenna_z = Head_length/4;
#local Antenna_x = Head_width/4;
#local Antenna_bend_rad = Antenna_bend_deg*pi/180;
#local Antenna_aux = Antenna_length/Antenna_bend_rad;

#local head =
  union {
    isosurface {
      function {1/2
        -mix(1-mix_eps_main,1+mix_eps_main,1,0,outer(
          -Nose_length,-Nose_length+Nose_tip_length,
          -Head_length,0,
          -Head_length/2,0,
          0,Head_length/2,
          Nose_width/2,Nose_height/2,(Head_height-Nose_height)/2,
          Head_width/2,Head_height/2,0,
          x,y,z))
        -mix(1-mix_eps_neck,1+mix_eps_neck,1,0,
          pow(x/Neck_rad,2)+
          pow((y*cos(Neck_ang_rad)+z*sin(Neck_ang_rad))/Neck_rad,2)+
          pow((z*cos(Neck_ang_rad)-y*sin(Neck_ang_rad)-Neck_hlen)/Neck_hlen,2))
        -mix(1-mix_eps_antenna,1+mix_eps_antenna,1,0,
          round_bar
            (Antenna_bend_rad,Antenna_aux,Antenna_rad,
            abs(x)-Antenna_x,y-Head_height/2,z-Antenna_z+Antenna_aux))
        +mix(1-mix_eps_eyes,1+mix_eps_eyes,1,0,
          pow((abs(x)-Eye_x)/Eye_rad,2)+
          pow((y-Eye_y)/Eye_rad,2)+pow((z-Eye_z)/Eye_rad,2))}
      threshold 0
      contained_by {box {
        <-Head_width/2,-Neck_length,-Nose_length>-1/2
        <Head_width/2,Head_height/2+Antenna_length,Neck_length>+1/2}}
      max_gradient 100
      texture {Chitin_texture}
    }
    object {eye}
    object {eye scale <-1,1,1>}
    rotate -Neck_ang_deg*x
    translate -Neck_hlen*z
    scale Head_scale
  }

#local Hair_wind_bend_rad = Hair_wind_bend_deg*pi/180;
#local Hair_num_segments = 2;
#local Hair_length = 4;
#local Hair_aux1 = Hair_length/Hair_wind_bend_rad;
#local Hair_rad = 1/10;
#local Hair_root_rad = 1.5;
#local Hair_scale = 1/16;

#local hair =
  sphere_sweep {
    b_spline
    Hair_num_segments+4
    <0,-2,0> 1
    <0,-1,0> 1
    #local i=0;
    #while (i<=Hair_num_segments+1)
      #local Angle=Hair_wind_bend_rad*i/Hair_num_segments;
      <0,Hair_aux1*sin(Angle),Hair_aux1*(1-cos(Angle))>
      #if (i<Hair_num_segments)
        Hair_rad
      #else
        0
      #end
      #local i=i+1;
    #end
    translate y
    scale Hair_scale
  }

#local Torso_jitter = 1;
#local Hair_max_dist = 2*Hair_root_rad*Hair_scale/sqrt(2)/(1+Torso_jitter);
#local Torso_num_hairs_len = ceil(Torso_length*1.3/Hair_max_dist);
#local Torso_stream = seed(1);
#local Torso_l_stripes = 4;
#local Torso_r_stripes = 6;
#local Torso_spiral_steepness = 1/Torso_l_stripes;

#local torso = union {
  #local i=0;
  #while (i<Torso_num_hairs_len)
    #local j=0;
    #local T0=(i+1/2)/Torso_num_hairs_len;
    #local Torso_num_hairs_circ = ceil(2*pi*(Torso_w(T0))/Hair_max_dist);
    #while (j<Torso_num_hairs_circ)
      #local T=(i+1/2+(rand(Torso_stream)-1/2)*Torso_jitter)
        /Torso_num_hairs_len;
      #local U=(j+1/2+(rand(Torso_stream)-1/2)*Torso_jitter)
        /Torso_num_hairs_circ;
					// mod does not work properly with
					// negative numbers. Hence 100+
      #local TT = mod(100+floor(T*Torso_l_stripes-Torso_phase),2);
      #local UU = mod(100+
        floor((U+T*Torso_spiral_steepness)*Torso_r_stripes-Torso_phase),2);
      object {
        hair
        #if (TT)
          #if (UU)
            texture{Hair_texture_LR}
          #else
            texture{Hair_texture_Lr}
          #end
        #else
          #if (UU)
            texture{Hair_texture_lR}
          #else
            texture{Hair_texture_lr}
          #end
        #end
        #local dy=Torso_dy(T);
        #local dz=Torso_dz(T);
        #local dw=Torso_dw(T);
        rotate -atanf(dw,dz)*180/pi*x	// not quite exact,
					// feel free to correct
        translate Torso_w(T)*y
        rotate U*360*z
        rotate -atanf(dy,dz)*180/pi*x
        translate <0,Torso_y(T),Torso_z(T)>
      }
      #local j=j+1;
    #end
    #local i=i+1;
  #end
}


#local mix_eps_rear = 0.5;
#local mix_tail_outer = 0.5;
#local mix_tail_inner = 0.5;

#local Rear_bend_rad = Rear_bend_deg*pi/180;
#local Rear_length = 1;
#local Rear_aux = Rear_length/Rear_bend_rad;
#local Rear_rad = 1/2;

#local Tail_outer_length = 2;
#local Tail_outer_rad = 1.5;
#local Tail_thickness = 0.5;
#local Tail_inner_pos = 0.5;
#local Tail_inner_length = Tail_outer_length+Tail_inner_pos-Tail_thickness;
#local Tail_inner_rad = Tail_outer_rad-Tail_thickness;
#local Tail_scale = 1/6;

#local tail =
  light_group {
    light_source {(Tail_thickness+1e-4)*z Eye_greyed_colour}
    isosurface {
      function {1/2
        -mix(1-mix_tail_outer,1+mix_tail_outer,1,0,
           pow(x/Tail_outer_rad,2)+
           pow(y/Tail_outer_rad,2)+
           pow((z-Tail_outer_length)/Tail_outer_length,2))
        +mix(1-mix_tail_inner,1+mix_tail_inner,1,0,
           pow(x/Tail_inner_rad,2)+
           pow(y/Tail_inner_rad,2)+
           pow((z-Tail_outer_length-Tail_inner_pos)/Tail_inner_length,2))
        -mix(1-mix_eps_rear,1+mix_eps_rear,1,0,
          round_bar(Rear_bend_rad,Rear_aux,Rear_rad,
            x,
            z*cos(Rear_bend_rad)+(y+Rear_aux)*sin(Rear_bend_rad),
            (y+Rear_aux)*cos(Rear_bend_rad)-z*sin(Rear_bend_rad)))}
      threshold 0
      contained_by {box {
        <-Tail_outer_rad,-max(Tail_outer_rad,Rear_length),-Rear_length>-1/2
        <Tail_outer_rad,Tail_outer_rad,Tail_outer_length+Tail_inner_pos>-1/2}}
      max_gradient 10
      texture {Chitin_texture}
    }
    translate Rear_aux*y
    rotate Rear_bend_deg*x
    translate -Rear_aux*y
    scale Tail_scale
    global_lights on
  }

#local insect =
  union {
    object {
      head
      #local dy=Torso_dy(0);
      #local dz=Torso_dz(0);
      rotate -atanf(dy,dz)*180/pi*x
      translate <0,Torso_y(0),Torso_z(0)>
    }
    object {torso}
    object {
      tail
      #local dy=Torso_dy(1);
      #local dz=Torso_dz(1);
      rotate -atanf(dy,dz)*180/pi*x
      translate <0,Torso_y(1),Torso_z(1)>
    }
    #if (playerKilled)
      translate -2*y
      rotate 90*z
      translate Torso_w_max*y
    #end
    rotate playerAngle
    translate playerLocation
    translate <0,0,-2>
  }

object{insect}

#version outer_version;

