 #declare ts_leafsize=.5;       //initializing Tree Sub Constants
 #declare ts_leaves_br=3;
 #declare ts_treetype=1;
 #declare ts_lengthf=.5;   
 #declare ts_doubranchprob=0;
 #declare ts_gravity=<0,-.02,0>;
 #declare ts_staging=.5;
 #declare ts_angularity=.5;        
 #declare ts_spline=1;
 #declare ts_wood=1; //parse wood
 #declare gs_gravity=<0,-.2,0>; //initializing Grass Sub Constants                 
 #declare gs_memspeed=1;  //0=less memory,slow render 
 #declare gs_detailed=1; //0=only cones
 #include"woods.inc"
 #include"math.inc" 
 
 #declare fnveg=   // basic vegetation shape function
  function{        // you may change it in your master pov-file
    pigment {
    bozo
    turbulence 0.4
    octaves 4
    omega .9
    lambda 4.3
      color_map {
        [0.0 color rgb 0.0]
        [0.4 color rgb 0.3]
        [0.5 color rgb 0.7]
        [1.0 color rgb 1.0]
      }
      scale 15 
      translate <0,0, 0>
    }
  } 



 #declare T_Tree=
  texture {
    pigment {
      agate
      color_map {  
        [0.0 color rgbt 1]
        [0.85 color rgbt 1]
        [0.85 color rgb <0.2, 0.5, 0.10> ]
        [0.89 color rgb <0.4, 0.6, 0.15> ]
        [0.98 color rgb <0.4, 0.6, 0.15> ]
        [0.99 color rgb <0.4, 0.2, 0.05> ]
      }
      scale 0.5
      warp { turbulence 0.9 }
    }
    finish {
      diffuse 0.7
      specular .5
      //brilliance 1.5
      //ambient 0.07
    }
    normal {
      wrinkles 0.6
      scale 0.5
    }
  } 
    
 #declare t_ltree=
  texture {
    pigment {
      bozo
      color_map {  
        [0.0 color rgb 1]
        [0.1 color rgb <0.5, 0.7, 0.20>]
        [0.2 color rgb <0.2, 0.5, 0.10> ]
        [0.4 color rgb <0.4, 0.6, 0.15> ]
        [0.9 color rgb <0.4, 0.6, 0.15> ]
        [1 color rgb <0.4, 0.2, 0.05> ]
      }
      scale 0.05
      warp { turbulence 0.9 }
    }
    finish {
      specular .5
      diffuse 0.7  //.9
      ambient 0  
      
      //reflection 0.02
    }
    normal {
      wrinkles 0.6
      scale 0.05
    }
  } 
     
  #declare t_tltree=
  texture {
    pigment {
      bozo
      color_map {  
        [0.0 color rgbt 1]
        [0.1 color rgbt <0.5, 0.7, 0.20,1>]
        [0.2 color rgbt <0.2, 0.5, 0.10,1> ]
        [0.4 color rgbt <0.4, 0.6, 0.15,1> ]
        [0.9 color rgbt <0.4, 0.6, 0.15,1> ]
        [1 color rgbt <0.4, 0.2, 0.05,1> ]
      }
      scale 0.05
      warp { turbulence 0.9 }
    }
    finish {
      specular .5
      diffuse 0.7  //.9
      ambient 0  
      
      //reflection 0.02
    }
    normal {
      wrinkles 0.6
      scale 0.05
    }
  }    
     

#declare leaf2ob=height_field { gif "blatt-ahorn2.gif"  smooth        // smooth surface normal
  water_level 90/256 // truncate/clip below N (0.0 ... 1.0)
  
   translate <0,0-90/256,0> scale <1,.05,1> rotate <0,-45,0> 
  }


#macro leaf2(posvec,dirvec,hrvec)  
  #local dhlpvec=<dirvec.x,0,dirvec.z>;
  #local ydirang=VAngleD(dhlpvec,z); 
  #local yhlpang=VAngleD(dhlpvec,x); 
  #local zdirang=VAngleD(dirvec,y)-90; 
  #local hhlpvec=vaxis_rotate(y,dirvec,90);
  #local hdirang=VRotationD(hrvec,y,dirvec);
  #local hhlpang=VRotationD(hrvec,hhlpvec,dirvec);
  #if (yhlpang>90)
   #local ydirang=-ydirang;
  #end
  #if (hhlpang<90)
   #local hdirang=-hdirang;
  #end
  object{leaf2ob 
  scale (vlength(dirvec)/1.41421) //7071
  rotate <0,0,hdirang>
  rotate <zdirang,0,0> 
  rotate <0,ydirang,0>
  translate posvec
  
   texture { t_ltree  }
  }

#end  




#macro troots(posvec,rcnt,brrad,brleng,stage) 

 #local cnt=rcnt;            
 #local nrad=sqrt(pow(brrad,2)/rcnt*1.0);
 #declare ts_treetype=1; 
 #declare ts_lengthf=.5;
 #declare ts_angularity=.2;
 #declare ts_staging=.25;
 #declare ts_wood=1; //parse wood
 #local gravbackup=ts_gravity;
 #while (cnt>0)
  #local ndir=vrotate(x,<0,360/rcnt*cnt,0>);
  #local npos=posvec+ndir*(brrad+nrad/2);
  #local ndir=ndir*brleng;
  #local nstage=int(fnveg(npos.x,npos.y,npos.z).gray*stage/2+1);
   #declare ts_gravity=<0,-0.2/nstage-.2,0>;
   twood(npos,ndir,<0,1,0>,nrad,brleng,60,180,nstage)
   sphere{npos+<0,nrad/2,0>,nrad*2,2}
  #local cnt=cnt-1;
 #end 
 #declare ts_gravity=gravbackup;
#end

 
#macro tree(qposvec,qdirvec,qhrvec,qbrrad,qbrleng,qxwink,qdwink,qstage,qxxwink,qxstage,qlfak,qttyp)
 union{
 #debug "parsing wood \n"
 blob{   threshold 1  
   sphere{qposvec,qbrrad*1.5,3 } 
 troots(qposvec,5,qbrrad,sin(radians(qxwink))*qbrleng/2,int(sqrt(qstage)+1))       
 #declare ts_treetype=qttyp;
 #declare ts_lengthf=qlfak;
 #declare ts_staging=qxstage;
 #declare ts_angularity=qxxwink;  
 #declare ts_wood=1; //parse wood

 twood(qposvec,qdirvec,qhrvec,qbrrad,qbrleng,qxwink,qdwink,qstage)

  texture { T_Wood2 scale .05 rotate <0,0,90> scale <1,3,1> translate qposvec}  
  }        
 #if (qttyp=3) 
 #else
  #declare ts_wood=0; //parse leaves
  #debug "parsing leaves \n"
  twood(qposvec,qdirvec,qhrvec,qbrrad,qbrleng,qxwink,qdwink,qstage)
 #end
 }
#end
  
        
#macro twood(posvec,dirvec,hrvec,brrad,brleng,xwink,dwink,stage)
 #local ldirvec=vlength(dirvec)*vnormalize((dirvec*(1-vlength(ts_gravity))+vlength(dirvec)*ts_gravity));
 #local nposvec=posvec+ldirvec;                                               
 #if (stage>1) 
  #local astage=int(fnveg(posvec.x,posvec.y,posvec.z).gray*stage*ts_staging+1);  
  #if (astage>(stage-1)) #local astage=stage-1;  #end 
  #if (astage<1) #local astage=1; #end 
  #local nstage=int(stage-astage);        
  #if (nstage<1) #local nstage=1; #end 
  #local ndwink=dwink+dwink*(fnveg(nposvec.x,nposvec.y,nposvec.z).gray-.5)*ts_angularity;  
  #local aquer=pow(brrad,2);
  #local nrad=sqrt(aquer/stage*nstage);
  #local arad=sqrt(aquer/stage*astage); 
  #if (arad=0) #local arad=brrad/stage; #end           
  #if (nrad=0) #local nrad=brrad/stage; #end           
  #local aleng=brleng*(1-ts_lengthf)+brleng/(astage+nstage)*astage*ts_lengthf;
  #local nleng=brleng*(1-ts_lengthf)+brleng/(astage+nstage)*nstage*ts_lengthf;
  #local kwink=(xwink*fnveg(nposvec.x,nposvec.y,nposvec.z).gray*ts_angularity);
  #local adirvec=(vnormalize(ldirvec)*aleng);
  #local ndirvec=(vnormalize(ldirvec)*nleng); 
  #local adirvec=vaxis_rotate(adirvec,hrvec,kwink-xwink);
  #local ndirvec=vaxis_rotate(ndirvec,hrvec,kwink);
  #local adirvec=vaxis_rotate(adirvec,ldirvec,ndwink);
  #local ndirvec=vaxis_rotate(ndirvec,ldirvec,ndwink);   
  #local nrvec=vaxis_rotate(hrvec,ldirvec,ndwink);
  #local aposvec=nposvec;
  #if (ts_treetype>3)
   #local adirvec=<adirvec.x,abs(adirvec.y),adirvec.z>;
   #local ndirvec=<ndirvec.x,abs(ndirvec.y),ndirvec.z>;  
   #local arad=sqrt(pow(arad,2)/2);
  #else     
   #local dot_dirvec=vdot(dirvec,nrvec);                         
   #if (vlength(dot_dirvec)>0)
    #local aposvec=nposvec+vnormalize(dot_dirvec)*(brrad-arad);
    #local nposvec=nposvec-vnormalize(dot_dirvec)*(brrad-nrad);
   #end 
  #end
  #if (ts_wood=1)
   #if (ts_spline<2)
    sphere{posvec,brrad*1.5,-4 }  
    cylinder{posvec,posvec+ldirvec,brrad*1.5,4}     
   #else   
    #local spdirvec=ldirvec-(ndirvec*pow(nrad,2)+adirvec*pow(arad,2))/pow(brrad,2);
    #local spadirvec=(dirvec-ldirvec)/2;
    #local spleng=int((brleng/brrad)+1);  
    #if (spleng>ts_spline) #local spleng=ts_spline; #end
    #local spcount=spleng-1;                        
    #local pos1=posvec;
    #while (spcount>-1)                 
     #local spraise=(spleng-spcount)/spleng;
     #local spfall=spcount/spleng;
     #local pos2=posvec+ldirvec*spraise+spdirvec*pow(spraise,2)*spfall+spadirvec*pow(spfall,2)*spraise;
     sphere{pos1,brrad*1.5,-4 }  
     cylinder{pos1,pos2,brrad*1.5,4}     
     #local spcount=spcount-1;
     #local pos1=pos2;
    #end
   #end     
   #if (stage>4)
    #local xvec=brrad*2*vnormalize(nrvec);
    #local xpos=posvec+ldirvec;//-vnormalize(ldirvec)*brrad/2;   
    #local xstr=arad*nrad/brrad/brrad;
    sphere{xpos-xvec,brrad*2.7,-xstr }    
    sphere{xpos+xvec,brrad*2.7,-xstr }
   #end         
  #end
   #if (stage>10) #debug concat("  parsing stage ",str(stage,4,0),"\n") #end
   
  //  #debug concat("leavesize:",str(ts_leafsize,1,2),"treetype:",str(ts_treetype,1,1),"lenf:",str(ts_lengthf,1,2),
  //  "grav:",str(vlength(ts_gravity),1,2),"stagef:",str(ts_staging,1,2),"angf:",str(ts_angularity,1,2),"wod:",str(ts_wood,1,1),"\n")
  //  #debug concat("stage:",str(stage,3,1)," new_stages:",str(astage,3,1),"/",str(nstage,3,1)," br_leng:",str(brleng,1,4)," new_rads:",str(arad,1,4),"/",str(nrad,1,4),"\n")
            
  twood(nposvec,ndirvec,nrvec,nrad,nleng,xwink,dwink,nstage) 
  #if (ts_doubranchprob>0)
   #if (ts_doubranchprob>1)
    #local doubranch=1;
   #else
    #local doubranch=fnveg(aposvec.x,aposvec.y,aposvec.z).gray*ts_doubranchprob;
   #end
   #if (doubranch>.5)                                        
    #local nstage=astage/2;
    #local aquer=astage;
    #if (nstage<1) #local nstage=1; #end 
    #if (nstage>int(nstage))
     #local nstage=int(nstage);
     #local astage=nstage+1;
    #else
     #local astage=nstage;
    #end  
    #local nrad=sqrt(pow(arad,2)/aquer*nstage);
    #local arad=sqrt(pow(arad,2)/aquer*astage); 
    twood(aposvec,adirvec,nrvec,arad,aleng,xwink,dwink,astage)
    #local aposvec=nposvec; //-aposvec;
    #local ndirvec=vaxis_rotate(adirvec,dirvec,180);
    #local adirvec=<ndirvec.x,adirvec.y,ndirvec.z>;
    #local nrvec=vaxis_rotate(nrvec,dirvec,180);
    twood(aposvec,adirvec,nrvec,nrad,aleng,xwink,-dwink,nstage)
   #else
    twood(aposvec,adirvec,nrvec,arad,aleng,xwink,dwink,astage) 
   #end
  #else 
   twood(aposvec,adirvec,nrvec,arad,aleng,xwink,dwink,astage) 
  #end 
 #else
  #if (ts_wood=1)
   #if (ts_spline<2)
    sphere{posvec,brrad*1.5,-4 }  
    cylinder{posvec,posvec+ldirvec,brrad*1.5,4}     
   #else   
    #local spadirvec=(dirvec-ldirvec)/2;
    #local spdirvec=spadirvec*3;
    #local spleng=int((brleng/brrad)+1); 
    #if (spleng>ts_spline) #local spleng=ts_spline; #end
    #local spcount=spleng-1;                        
    #local pos1=posvec;
    #while (spcount>-1)                 
     #local spraise=(spleng-spcount)/spleng;
     #local spfall=spcount/spleng;
     #local pos2=posvec+ldirvec*spraise+spdirvec*pow(spraise,2)*spfall+spadirvec*pow(spfall,2)*spraise;
     sphere{pos1,brrad*1.5,-4 }  
     cylinder{pos1,pos2,brrad*1.5,4}     
     #local spcount=spcount-1;
     #local pos1=pos2;
    #end
   #end     
  #else
   #if (ts_treetype=1)
    lhull(posvec,ldirvec,brrad,xwink)
   #else
    #if (ts_treetype<3)   
     leaves(posvec,ldirvec,hrvec,brrad,xwink)         
    #else   
     #if (ts_treetype=4)   
      nhull(posvec,ldirvec,brrad,xwink)
     #end
    #end 
   #end
  #end 
 #end 
 #if (ts_wood=0)
  #if (stage<3)
   #if (ts_treetype>4)
    needles(posvec,ldirvec,brrad,xwink)
   #end   
  #end  
 #end 
#end 

#macro leaves(posvec,dirvec,hrvec,brrad,xwink)
 #local nleng=vlength(dirvec);
 #local nposvec=posvec+dirvec;      
 #local lgravity=ts_gravity+<0,-.2,0>;
 #local ndirvec=vnormalize(dirvec)*ts_leafsize;
 #local adirvec=vaxis_rotate(ndirvec,hrvec,90);   
 #local bdirvec=vaxis_rotate(ndirvec,hrvec,-90);   
 #local ndirvec=vlength(ndirvec)*vnormalize((ndirvec*(1-vlength(lgravity))+vlength(ndirvec)*lgravity));
 #local adirvec=vlength(adirvec)*vnormalize((adirvec*(1-vlength(lgravity))+vlength(adirvec)*lgravity));
 #local bdirvec=vlength(bdirvec)*vnormalize((bdirvec*(1-vlength(lgravity))+vlength(bdirvec)*lgravity));
 #local nrvec=vdot(ndirvec,<adirvec.x,0,adirvec.z>);
 #local arvec=vdot(adirvec,<ndirvec.x,0,ndirvec.z>);
 #local brvec=vdot(bdirvec,<ndirvec.x,0,ndirvec.z>);
 #if (ts_leaves_br>1) union{ #end
 #if (mod(ts_leaves_br,2)=1) leaf2 (nposvec,ndirvec,nrvec) #end
 #local icnt=int(ts_leaves_br/2);
 #local cnt=icnt;
 #while (cnt>0)
  #local xpos=posvec+dirvec/icnt*cnt;
   leaf2 (xpos,adirvec,arvec)
   leaf2 (xpos,bdirvec,brvec) 
   #local adirvec=vaxis_rotate(adirvec,dirvec,xwink);
   #local bdirvec=vaxis_rotate(bdirvec,dirvec,xwink);
   #local adirvec=vlength(adirvec)*vnormalize((adirvec*(1-vlength(lgravity))+vlength(adirvec)*lgravity));
   #local bdirvec=vlength(bdirvec)*vnormalize((bdirvec*(1-vlength(lgravity))+vlength(bdirvec)*lgravity));
   #local arvec=vdot(adirvec,<ndirvec.x,0,ndirvec.z>);
   #local brvec=vdot(bdirvec,<ndirvec.x,0,ndirvec.z>);
  #local cnt=cnt-1;
 #end  
 #if (ts_leaves_br>1) } #end
#end

#macro lhull(posvec,dirvec,brrad,xwink)
 #local brleng=vlength(dirvec);
 #local nposvec=posvec+dirvec;
 #local brleng=vlength(dirvec);
   sphere {0,brleng
    scale<1,.4,1>     
    texture { T_Tree scale .2 translate fnveg(nposvec.x,nposvec.y,nposvec.z).gray*6 }
    translate nposvec}
#end
#macro needles(posvec,dirvec,brrad,xwink)
 #local brleng=vlength(dirvec);

 #local icnt=int(brleng/2/brrad);
 #local cnt=icnt;
 #local xdirvec=vnormalize(vaxis_rotate(dirvec,<dirvec.z,dirvec.x,dirvec.y>,xwink))*ts_leafsize/4;
 blob{
 #while (cnt>0)
  #local xpos=posvec+dirvec/icnt*cnt;
  #local xdirvec=vaxis_rotate(xdirvec,dirvec,720*fnveg(xpos.x,xpos.y,xpos.z).gray);
  #local ydirvec=vaxis_rotate(xdirvec,dirvec,90);
  #local adirvec=vaxis_rotate(ydirvec,dirvec,90);
  #local bdirvec=vaxis_rotate(adirvec,dirvec,90);

  cylinder {xpos,xpos+xdirvec,brrad/2,2}
  cylinder {xpos,xpos+ydirvec,brrad/2,2}
  cylinder {xpos,xpos+adirvec,brrad/2,2}
  cylinder {xpos,xpos+bdirvec,brrad/2,2}
  sphere {xpos,brrad/2,-5} 
  #local cnt=cnt-1;
 #end  
 texture { t_ltree }  }  
 
#end
#macro nhull(posvec,dirvec,brrad,xwink)
    #local nposvec=posvec+dirvec;                       
    #local xposvec=nposvec+vaxis_rotate(dirvec,y,xwink);
    #local yposvec=nposvec+vaxis_rotate(dirvec,y,-xwink);
    union {
    cylinder {posvec+dirvec/8+<0,brrad,0>,nposvec+dirvec+<0,brrad,0>,brrad*2}
    cylinder {nposvec+<0,brrad,0>,xposvec+<0,brrad,0>,brrad*2                }
    cylinder {nposvec+<0,brrad,0>,yposvec+<0,brrad,0>,brrad*2                 }
    texture { T_Tree scale .1 translate fnveg(nposvec.x,nposvec.y,nposvec.z).gray*6 }}
#end

#macro grasleaf(posvec,dirvec,hrvec,stage,wink)
 #local ldirvec=vlength(dirvec)*vnormalize((dirvec*(1-vlength(gs_gravity))+vlength(dirvec)*gs_gravity));
 #local ldirvec=vaxis_rotate(ldirvec,-hrvec,wink);
 #local ndirvec=vlength(ldirvec)*vnormalize((ldirvec*(1-vlength(gs_gravity))+vlength(ldirvec)*gs_gravity));
 #local ndirvec=vaxis_rotate(ndirvec,-hrvec,wink);
 #local nposvec=posvec+ldirvec;                                               
 #local nrvec=hrvec*(stage-1)/stage;
    #local spdirvec=(ldirvec+ndirvec)/2;
    #local spadirvec=(dirvec+ldirvec)/2;
    #local pos1=posvec;
    #local pos2=posvec+ldirvec;
    #local hrv1=hrvec;
    #local hrv2=(hrvec*2+nrvec)/3;
    #local hrv3=(hrvec+nrvec*2)/3;
    #local hrv4=nrvec;
    #local ddv1=vnormalize(vaxis_rotate(hrvec,spadirvec,90))*vlength(hrv1);
    #local ddv2=vnormalize(vaxis_rotate(hrvec,(spadirvec*2+spdirvec)/3,90))*vlength(hrv2);
    #local ddv3=vnormalize(vaxis_rotate(hrvec,(spadirvec+spdirvec*2)/3,90))*vlength(hrv3);
    #local ddv4=vnormalize(vaxis_rotate(hrvec,spdirvec,90))*vlength(hrv4);

bicubic_patch {
		type gs_memspeed
		flatness 0
		u_steps 3
		v_steps 3
		pos1        +.40*ddv1 pos1+spadirvec/3        +.40*ddv2 pos2-spdirvec/3        +.40*ddv3 pos2        +.40*ddv4
		pos1+.1*hrv1+.35*ddv1 pos1+spadirvec/3+.1*hrv2+.35*ddv2 pos2-spdirvec/3+.1*hrv3+.35*ddv3 pos2+.1*hrv4+.35*ddv4 
		pos1+.5*hrv1+.10*ddv1 pos1+spadirvec/3+.5*hrv2+.10*ddv2 pos2-spdirvec/3+.5*hrv3+.10*ddv3 pos2+.5*hrv4+.10*ddv4 
		pos1+ 1*hrv1          pos1+spadirvec/3+ 1*hrv2          pos2-spdirvec/3+ 1*hrv3          pos2+ 1*hrv4 
	}
bicubic_patch {
		type gs_memspeed
		flatness 0
		u_steps 3
		v_steps 3
		pos1        +.40*ddv1 pos1+spadirvec/3        +.40*ddv2 pos2-spdirvec/3        +.40*ddv3 pos2        +.40*ddv4
		pos1-.1*hrv1+.35*ddv1 pos1+spadirvec/3-.1*hrv2+.35*ddv2 pos2-spdirvec/3-.1*hrv3+.35*ddv3 pos2-.1*hrv4+.35*ddv4 
		pos1-.5*hrv1+.10*ddv1 pos1+spadirvec/3-.5*hrv2+.10*ddv2 pos2-spdirvec/3-.5*hrv3+.10*ddv3 pos2-.5*hrv4+.10*ddv4 
		pos1- 1*hrv1          pos1+spadirvec/3- 1*hrv2          pos2-spdirvec/3- 1*hrv3          pos2- 1*hrv4 
	}
   #if (stage>1)
    grasleaf(nposvec,ldirvec,nrvec,stage-1,wink)
   #end         
 #end     


#macro bgras(posvec,leng,xleng,gd,anz)
 #local cnt=anz;
 union{
 #while (cnt>0)      
  #local nvec=vrotate(<leng,0,0>,<0,360/anz*cnt,0>);
  #local xvec=vrotate(nvec,<0,-90,0>);
  #local npos=(posvec+nvec)*500;
  #local upwink=int((fnveg(npos.x,npos.y,npos.z).gray)*180);  
  #local nvec=vaxis_rotate(nvec,xvec,upwink);
  #local npos=(posvec+nvec)*300;
  #local nleng=(leng+(fnveg(npos.x,npos.y,npos.z).gray-.5)*leng*xleng);  
  #local npos=posvec+vnormalize(nvec)*nleng;
  #if (gs_detailed=0)
   cone{posvec,gd,npos,0} 
  #else
   grasleaf(posvec-vnormalize(nvec)*gd/2,<0,nleng/2,0>,vnormalize(xvec)*gd,2,upwink/3)
  #end
  #local cnt=cnt-1;
 #end          
 pigment { rgb <0.2, 0.5, 0.25> }
 finish { phong 0.9 } }  
#end
 