///////////////////////////////////////////////////////////////////
////////////// Lego Block creation macro //////////////////////////
///////////////////////////////////////////////////////////////////

#macro lego(w,l,h,col)
          #local lego_cyl = //Little nub on top
            cylinder{ <2.5,h,2.5> <2.5,h+1,2.5>, 1.4 }
          #local j1 = 0; //General counters
          #local j2 = 0;
          #local prot1 = //All nubs aligned in place
          union{
            #while ( j1 < w )
              #while ( j2 < l )
                object{ lego_cyl translate <5*j1,0,5*j2> }
                #local j2 = j2 + 1;
              #end
              #local j2 = 0;
              #local j1 = j1 + 1;
            #end
            box{ <.1,.2,.1> <w*5-.1,h,l*5-.1> } //Outside shape
          }
          #local cut1 =
          box{ <.7,0,.7> <w*5-.7,h-.7,l*5-.7> } //Inside box to create wall thickness
          #local j1 = 0; //General counters
          #local j2 = 0;
          #local prot2 = //Protrusion on bottom of block
            union{
              #if ( w < 2 | l < 2 ) //Solid Cylinder for 1x blocks
                #while ( j1 < l-1 )
                  cylinder{ <2.5,0,5*j1+5> <2.5,h,5*j1+5>, 1.1 }
                  #local j1 = j1 + 1;
                #end
              #else
                #while ( j1 < w-1 ) //Hollow cylinder for 2x+ blocks
                  #while ( j2 < l-1 )
                    difference{
                      cylinder{ <5*j1+5,0,5*j2+5> <5*j1+5,h,5*j2+5>, 2 }
                      cylinder{ <5*j1+5,-.1,5*j2+5> <5*j1+5,h+.1,5*j2+5>, 1.6 }
                    }
                    #local j2 = j2 + 1;
                  #end
                  #local j2 = 0;
                  #local j1 = j1 + 1;
                #end  
              #end
              sphere{ <0,0,0>, 0 } //These stop errors of < 2 objects in union
              sphere{ <0,0,0>, 0 }
          }
          #if ( col.x = 0 & col.y = 0 & col.z = 0 ) //If passed black, assigns random color
            #switch ( rand(bob) ) 
              #range ( 0,.1 )
                #declare col = <.2,.2,.2>;
              #break
              #range ( .1,.4 )
                #declare col = <1,.2,.2>;
              #break
              #range ( .4,.6 )
                #declare col = <1,.9,.2>;
              #break
              #range ( .6,.9 )
                #declare col = <.2,.3,1>;
              #break
              #range ( .9,1 )
                #declare col = <1,1,1>;
              #break
            #end
          #end  
          #declare lego_tex =
            texture{
              pigment{ color rgb col }
              finish{ ambient .3 diffuse 1.2 phong .4 phong_size 50 }
            }
          union{           //Final lego block, spans +x, +y, +z
            difference{
              object{ prot1 }
              object{ cut1 }
            }
            object{ prot2 }
            texture{ lego_tex }
          }
#end

////////////////////////////////////////////////////
////////////// Random Block Placer /////////////////
////////////////////////////////////////////////////


#declare j1 = 0;
#declare num = 60;
#declare sd_val = 212;
#declare bob = seed(sd_val);
#declare spread_r = 500;

#declare rand_blocks =
union{
        #while ( j1 < num )
          #switch ( rand(bob) ) // Height of Lego Block
            #range ( 0,.8 )
              #declare h = 6;
            #break
            #range ( .8,1 )
              #declare h = 2;
            #break
          #end
          #switch ( rand(bob) ) // Width of Lego Block
            #range ( 0,.3 )
              #declare w = 1;
            #break
            #range ( .3,1 )
              #declare w = 2;
            #break
          #end
          #switch ( rand(bob)+.1*rand(bob) ) // Length of Lego Block
            #range ( 0,.2 )
              #declare l = 1;
            #break
            #range ( .3,.6 )
              #declare l = 2;
            #break
            #range ( .6,.85 )
              #declare l = 4;
            #break
            #range ( .85,.95 )
              #declare l = 6;
            #break
            #range ( .95,1 )
              #declare l = 8;
            #break
          #end  
          #switch ( rand(bob)+.1*rand(bob) ) // Color of Lego Block
            #range ( 0,.28 )
              #declare col = <.1,.1,1>;
            #break
            #range ( .28,.56 )
              #declare col = <1,.1,.1>;
            #break
            #range ( .56,.84 )
              #declare col = <1,1,.1>;
            #break
            #range ( .84,.92 )
              #declare col = <.05,.05,.05>;
            #break
            #range ( .92,1 )
              #declare col = <1,1,1>;
            #break
          #end
          #declare size_tst1 = w + l;
          #declare rot = <0,0,0>;
          #declare trans = <0,0,0>;
          #if ( h > 2 & rand(bob) > .5 )
            #declare rot = <0,0,90>;
          #end
          #if ( h > 1 & w > 1 & rand(bob) > .7 )
            #declare rot = <0,0,180>;
            #declare trans = <0,h+1,0>;
          #end
          #declare lego_tex =
            texture{
              pigment{ color rgb col }
              finish{ phong .98 phong_size 20 }
            }
          object{ 
            lego(w,l,h,<0,0,0>)
            rotate rot
            translate trans
            rotate 360*(rand(bob)+rand(bob)*.1+rand(bob)*.01)*y 
            translate (rand(bob)-.5)*spread_r*x 
            translate (rand(bob)-.5)*spread_r*z 
          }
          #declare j1 = j1 + 1;
        #end
        translate <100,0,100>
}

/////////////////////////////////////////////////////////////
//////////////////// Castle Towers //////////////////////////
/////////////////////////////////////////////////////////////


#declare S1 = seed(99492);
#declare height = 0;
#declare height_max = 70;
#declare cap_height = 30;

#declare tower =
        union{
        #while ( height < height_max ) //Tower Walls
          union{
            object{ lego(2,4,6,<0,0,0>) rotate 90*y translate <0,0,10> }
            object{ lego(2,6,6,<0,0,0>) rotate 0*y translate <0,0,10> }
            object{ lego(2,4,6,<0,0,0>) rotate 90*y translate <0,0,50> }
            object{ lego(2,2,6,<0,0,0>) rotate 0*y translate <30,0,0> }
            object{ lego(2,4,6,<0,0,0>) rotate 0*y translate <40,0,0> }
            object{ lego(2,6,6,<0,0,0>) rotate 90*y translate <20,0,50> }
            object{ lego(2,2,6,<0,0,0>) rotate 0*y translate <40,0,30> }
            translate <0,height,0>
          }
          #declare height = height + 6;
          #if ( height < height_max )
            union{
              object{ lego(2,4,6,<0,0,0>) rotate 90*y translate <0,0,10> }
              object{ lego(2,6,6,<0,0,0>) rotate 0*y translate <0,0,10> }
              object{ lego(2,4,6,<0,0,0>) rotate 90*y translate <0,0,50> }
              object{ lego(2,2,6,<0,0,0>) rotate 0*y translate <30,0,0> }
              object{ lego(2,4,6,<0,0,0>) rotate 0*y translate <40,0,0> }
              object{ lego(2,6,6,<0,0,0>) rotate 90*y translate <20,0,50> }
              object{ lego(2,2,6,<0,0,0>) rotate 0*y translate <40,0,30> }
              scale <-1,1,1> rotate -90*y translate <50,height,50>
            }
            #declare height = height + 6;
          #end
        #end
        object{ lego(12,12,2,<0,0,0>) translate <-5,height,-5> } //Plate
        #declare height = height + 2;
        #while ( height < height_max+cap_height ) //Tower Cap
          union{
            object{ lego(1,4,6,<0,0,0>) rotate 90*y translate <0,0,0> }
            object{ lego(1,3,6,<0,0,0>) rotate 90*y translate <20,0,0> }
            object{ lego(1,4,6,<0,0,0>) rotate 90*y translate <35,0,0> }
            object{ lego(1,4,6,<0,0,0>) rotate 0*y translate <50,0,0> }
            object{ lego(1,3,6,<0,0,0>) rotate 0*y translate <50,0,20> }
            object{ lego(1,4,6,<0,0,0>) rotate 0*y translate <50,0,35> }
            object{ lego(1,4,6,<0,0,0>) rotate 90*y translate <-5,0,55> }
            object{ lego(1,3,6,<0,0,0>) rotate 90*y translate <15,0,55> }
            object{ lego(1,4,6,<0,0,0>) rotate 90*y translate <30,0,55> }
            object{ lego(1,4,6,<0,0,0>) rotate 0*y translate <-5,0,-5> }
            object{ lego(1,3,6,<0,0,0>) rotate 0*y translate <-5,0,15> }
            object{ lego(1,4,6,<0,0,0>) rotate 0*y translate <-5,0,30> }
            translate <0,height,0>
          }
          #declare height = height + 6;
          #if ( height < height_max+cap_height )
            union{
            object{ lego(1,4,6,<0,0,0>) rotate 90*y translate <0,0,0> }
            object{ lego(1,3,6,<0,0,0>) rotate 90*y translate <20,0,0> }
            object{ lego(1,4,6,<0,0,0>) rotate 90*y translate <35,0,0> }
            object{ lego(1,4,6,<0,0,0>) rotate 0*y translate <50,0,0> }
            object{ lego(1,3,6,<0,0,0>) rotate 0*y translate <50,0,20> }
            object{ lego(1,4,6,<0,0,0>) rotate 0*y translate <50,0,35> }
            object{ lego(1,4,6,<0,0,0>) rotate 90*y translate <-5,0,55> }
            object{ lego(1,3,6,<0,0,0>) rotate 90*y translate <15,0,55> }
            object{ lego(1,4,6,<0,0,0>) rotate 90*y translate <30,0,55> }
            object{ lego(1,4,6,<0,0,0>) rotate 0*y translate <-5,0,-5> }
            object{ lego(1,3,6,<0,0,0>) rotate 0*y translate <-5,0,15> }
            object{ lego(1,4,6,<0,0,0>) rotate 0*y translate <-5,0,30> }
            scale <-1,1,1> rotate -90*y translate <50,height,50>
            }
            #declare height = height + 6;
          #end
        #end
        union{  //Arrow Notches
          object{ lego(1,3,6,<0,0,0>) rotate 90*y translate <5,0,0> }
          object{ lego(1,3,6,<0,0,0>) rotate 90*y translate <30,0,0> }
          object{ lego(1,3,6,<0,0,0>) rotate 0*y translate <50,0,5> }
          object{ lego(1,3,6,<0,0,0>) rotate 0*y translate <50,0,30> }
          object{ lego(1,3,6,<0,0,0>) rotate 90*y translate <5,0,55> }
          object{ lego(1,3,6,<0,0,0>) rotate 90*y translate <30,0,55> }
          object{ lego(1,3,6,<0,0,0>) rotate 0*y translate <-5,0,5> }
          object{ lego(1,3,6,<0,0,0>) rotate 0*y translate <-5,0,30> }
          object{ lego(1,1,6,<0,0,0>) rotate 0*y translate <-5,0,-5> }
          object{ lego(1,1,6,<0,0,0>) rotate 0*y translate <50,0,-5> }
          object{ lego(1,1,6,<0,0,0>) rotate 0*y translate <50,0,50> }
          object{ lego(1,1,6,<0,0,0>) rotate 0*y translate <-5,0,50> }
          object{ lego(1,1,6,<0,0,0>) rotate 0*y translate <10,6,-5> }
          object{ lego(1,1,6,<0,0,0>) rotate 0*y translate <35,6,-5> }
          object{ lego(1,1,6,<0,0,0>) rotate 0*y translate <50,6,10> }
          object{ lego(1,1,6,<0,0,0>) rotate 0*y translate <50,6,35> }
          object{ lego(1,1,6,<0,0,0>) rotate 0*y translate <10,6,50> }
          object{ lego(1,1,6,<0,0,0>) rotate 0*y translate <35,6,50> }
          object{ lego(1,1,6,<0,0,0>) rotate 0*y translate <-5,6,10> }
          object{ lego(1,1,6,<0,0,0>) rotate 0*y translate <-5,6,35> }
          translate <0,height,0>
        }
        translate <-25,0,-25> rotate -90*y
}

//////////////////////////////////////////////////
/////////////// Castle Walls /////////////////////
//////////////////////////////////////////////////

#declare h = 0;
#declare h_max = 50;
#declare w = 0;
#declare w_max = 150;


#declare wall =
union{
        #while ( h < h_max )
          #while ( w < w_max )
                  #switch ( rand(S1)+.1*rand(S1) ) // Length of Lego Block
                    #range ( 0,.2 )
                      #declare l = 1;
                    #break
                    #range ( .3,.6 )
                      #declare l = 2;
                    #break
                    #range ( .6,.85 )
                      #declare l = 4;
                    #break
                    #range ( .85,.95 )
                      #declare l = 6;
                    #break
                    #range ( .95,1 )
                      #declare l = 8;
                    #break
                  #end
            object{ lego(2,l,6,<0,0,0>) translate <0,h,w> }
            #declare w = w + l*5;
            #if ( w >= w_max-40 )
              object{ lego(2,(w_max-w)/5,6,<0,0,0>) translate <0,h,w> }
              #declare w = w_max + 1;
            #end
          #end
          #declare w = 0;
          #declare h = h + 6;
        #end
        #declare w = 0;
          #while ( w < w_max-40 )
              #declare w = w + 20;     
              object{ lego(2,3,6,<0,0,0>) translate <0,h,w> }
              object{ lego(2,1,6,<0,0,0>) translate <0,h+6,w+5> }
          #end
}

#declare castle =
  union{
    object{ rand_blocks }
    object{ tower }
    object{ tower rotate 90*y translate <0,0,150> }
    object{ tower rotate 180*y translate <150,0,150> }
    object{ tower rotate 270*y translate <150,0,0> }
    object{ wall rotate 0*y translate <-5,0,0> }
    object{ wall rotate 0*y translate <145,0,0> }
    object{ wall rotate 90*y translate <0,0,5> }
    object{ wall rotate 90*y translate <0,0,155> } 
  }