#include "rand.inc"
#declare torus_thickness=0.15; // radius of an *untransformed* torus segment

#declare num_phi1=36; // number of segments around minor torus axis
#declare num_phi2=5*4; // number of segments along 90 degrees of the major torus axis  


// These functions define the transformation of the 3D Trouchet tiling
// Change them if you like
 
#declare point_trans_x=function(x,y,z) {
// x*sin(y/4)+z*cos(y/4)
 x/max(1e-6,x*x+y*y+z*z)
} 
#declare point_trans_y=function(x,y,z) {
// y
 y/max(1e-6,x*x+y*y+z*z)
} 
#declare point_trans_z=function(x,y,z) {
// x*cos(y/4)-z*sin(y/4)
 z/max(1e-6,x*x+y*y+z*z)
} 

// This generates one point on the torus surface (phi1: along major, phi2: along minor axis)
#macro _point(phi1,phi2)
 (vrotate(vrotate(torus_thickness*z,x*phi2)+z*1,y*phi1))
#end                                                                                        
// Same for the normals
#macro _normal(phi1,phi2)
 (vrotate(vrotate(z,phi2*x),phi1*y))
#end

#declare step_phi1=90/num_phi1; // angular step sizes
#declare step_phi2=360/num_phi2;

// This generates triangles of one quarter torus
// trans,rot is used for positioning the torus whithin the origin tile
// trans2,rot2 is used for translating/rotating the final tile

#macro _quarter_torus_tris(trans,rot,trans2,rot2)
 #local _phi1=0;
 #while (_phi1<90) 
  #local _phi2=0;
  #while (_phi2<360) 
   #local p1=vrotate(vrotate(_point(_phi1,_phi2),rot)+trans,rot2)+trans2;
   #local p2=vrotate(vrotate(_point(_phi1+step_phi1,_phi2),rot)+trans,rot2)+trans2;
   #local p3=vrotate(vrotate(_point(_phi1+step_phi1,_phi2+step_phi2),rot)+trans,rot2)+trans2;
   #local p4=vrotate(vrotate(_point(_phi1,_phi2+step_phi2),rot)+trans,rot2)+trans2;
   

   #local p1=<point_trans_x(p1.x,p1.y,p1.z),point_trans_y(p1.x,p1.y,p1.z),point_trans_z(p1.x,p1.y,p1.z)>;
   #local p2=<point_trans_x(p2.x,p2.y,p2.z),point_trans_y(p2.x,p2.y,p2.z),point_trans_z(p2.x,p2.y,p2.z)>;
   #local p3=<point_trans_x(p3.x,p3.y,p3.z),point_trans_y(p3.x,p3.y,p3.z),point_trans_z(p3.x,p3.y,p3.z)>;
   #local p4=<point_trans_x(p4.x,p4.y,p4.z),point_trans_y(p4.x,p4.y,p4.z),point_trans_z(p4.x,p4.y,p4.z)>;
// This section is commented out, since I have no clue how to transform the normals apropriately
/*   
   #local n1=vrotate(vrotate(_normal(_phi1,_phi2),rot),rot2);
   #local n2=vrotate(vrotate(_normal(_phi1+step_phi1,_phi2),rot),rot2);
   #local n3=vrotate(vrotate(_normal(_phi1+step_phi1,_phi2+step_phi2),rot),rot2);
   #local n4=vrotate(vrotate(_normal(_phi1,_phi2+step_phi2),rot),rot2);
   smooth_triangle{p1,n1,p2,n2,p3,n3}
   smooth_triangle{p1,n1,p3,n3,p4,n4}
*/
   triangle {p1,p2,p3}
   triangle {p1,p3,p4}
   #local _phi2=_phi2+step_phi2;
  #end
  #local _phi1=_phi1+step_phi1;
 #end
#end

// This generates triangles for one complete tile with 3 quarter tori
#macro Trouchet_Tile(trans,rot) 
 _quarter_torus_tris(<-1,0,-1>,0,trans,rot)
 _quarter_torus_tris(<1,1,0>,<90,180,0>,trans,rot)
 _quarter_torus_tris(<0,-1,1>,<0,90,90>,trans,rot)
#end

// One stupid texture... comming up!
#declare Tpipes=texture {
 pigment { color rgbf <0.7,0.9,0.99,00> }
 finish { specular 1 roughness 0.1 reflection 0.1}
}

// Boring camera and lighting setup
camera {
 location 3
 look_at 0
 angle 45
 rotate y*20
}        

light_source {
 1000
 color rgb 1
 rotate y*90
}
light_source {
 1000
 color rgb <1,.6,.6>
 rotate -y*100
}

// The seed for the 3D tiling
#declare rotseed=seed(2345443);
// This is the size of the tiling in cubes along each axis,
// should be multiple of 2 but works with any value
#declare _size=4;

// now this generates the final mesh
#declare Trouchet=mesh{
#declare _x=-_size/2;
#while (_x<=_size/2)    
 #declare _y=-_size/2;
 #while (_y<=_size/2)    
  #declare _z=-_size/2;
  #while (_z<=_size/2)
   #declare rx=int(RRand(0,3,rotseed))-1;
   #declare ry=int(RRand(0,3,rotseed))-1;
   #declare rz=int(RRand(0,3,rotseed))-1;
   
   Trouchet_Tile( <_x,_y,_z>*2 , <rx,ry,rz>*90 )
  
  
   #declare _z=_z+1;
  #end
  #declare _y=_y+1;
 #end
 #declare _x=_x+1;
#end                          
texture{Tpipes}
}                 

// and displays it                 
object {Trouchet}     

// and another dull background
background {
 color rgb <.85,.80,.90>*0.3  
}