// ========================================
// MakeSnow macro
// -----------------------------------------
// Made for Persistence of vision 3.6
//========================================== 
// Copyright 2003 Gilles Tran www.oyonale.com/
// -----------------------------------------
// This work is licensed under the Creative Commons Attribution License.
// To view a copy of this license, visit creativecommons.org/licenses/by/2.0/
// or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
// You are free:
// - to copy, distribute, display, and perform the work
// - to make derivative works
// - to make commercial use of the work
// Under the following conditions:
// - Attribution. You must give the original author credit.
// - For any reuse or distribution, you must make clear to others the license terms of this work.
// - Any of these conditions can be waived if you get permission from the copyright holder.
// Your fair use and other rights are in no way affected by the above.
//========================================== 
// This macro project blob elements on an object, making it look like it is covered by snow.
// It was first developed to be used on trees, and it works better on complex shapes than on flat ones.
// Note: this macro uses the trace() function. This means that every surface will be detected, including
// transparent ones used for media for instance.

// #declare Particles=12000; // number of snow particles
//      More particles = more parsing time and smoother effect
//      The macro loops until this number of "hits" is completed ("misses" do not count).

// #declare Size=2; // size of the largest snow particle
//       Sizes between 2 and 100 should be OK for objects whose size is expressed in centimetres

// #declare Thickness=1; // thickness of the particles
//    
// #declare MinHeight=0; // snow starts falling from this height ( 1 = max height of the object)
// #declare MaxHeight=1.1; // snow stops falling from this height  ( 1 = max height of the object)
//       Using MinHeight < 1 makes it possible to have snow on lower parts of the object that are protected
//       by overhangs, higher branches and such, but it may requires more particles to get a proper effect

// #declare Direction=-y+x*0.1+z*0.3; // Direction of gravity, wind etc.(-y = vertical, no wind)
//    
#include "transforms.inc"
#macro MakeSnow(Obj,Particles,Size,Thickness,MinHeight,MaxHeight,Direction)
    #ifndef (T_Snow)
        #local T_Snow=texture{
            pigment{rgb 1}
            finish{ambient 0 diffuse 1}
        }
    #end
    #ifndef (rd)
        #local rd=seed(2003);
    #end
    #local Obj2=object{Obj Reorient_Trans(-y,<-Direction.x,Direction.y,-Direction.z>)}
    #local Min=min_extent(Obj2);
    #local Max=max_extent(Obj2);
    blob{
        threshold 0.6
        #local i=0; // first layer
        #debug "first layer of snow\n"
        #while (i<Particles/3)
            #local Start=<Min.x+rand(rd)*(Max.x-Min.x),(MinHeight+rand(rd)*(MaxHeight-MinHeight))*Max.y,Min.z+rand(rd)*(Max.z-Min.z)>;
            #local Norm=<0,0,0>;
            #local Inter= trace (Obj2, Start, -y, Norm );
            #if (vlength(Norm)!=0)
                #local Angle=pow((180-abs(degrees(acos(min(1,vdot(vnormalize(Norm),y))))))/180,2);
                #local FlakeSize=Angle*<1+rand(rd)*1.3,(Angle*0.5+rand(rd))*Thickness,1+rand(rd)*1.3>;
                sphere{0,Size*2,1 scale FlakeSize Reorient_Trans(y,Norm) translate Inter}
                #if (mod(i,1000)=0)
                    #debug concat(str(i,0,0),"\n")
                #end
                #local i=i+1;
            #end
        #end
        #local  i=0;
        #debug "second layer of snow\n"
        #while (i<Particles*2/3) // second layer of smaller particles
            #local Start=<Min.x+rand(rd)*(Max.x-Min.x),(MinHeight+rand(rd)*(MaxHeight-MinHeight))*Max.y,Min.z+rand(rd)*(Max.z-Min.z)>;
            #local Norm=<0,0,0>;
            #local Inter= trace (Obj2, Start, -y, Norm );
            #if (vlength(Norm)!=0)
                #local Angle=pow((180-abs(degrees(acos(min(1,vdot(vnormalize(Norm),y))))))/180,2);
                #local FlakeSize=Angle*<1+rand(rd)*1.3,(Angle*0.5+rand(rd))*Thickness,1+rand(rd)*1.3>;
                sphere{0,Size*2,1 scale FlakeSize*0.25 Reorient_Trans(y,Norm) translate Inter}
                #if (mod(i,1000)=0)
                    #debug concat(str(i,0,0),"\n")
                #end
                #local i=i+1;
            #end
        #end
        texture{T_Snow}
        Reorient_Trans(<-Direction.x,Direction.y,-Direction.z>,-y)
    }
#end