// Persistence of Vision Ray Tracer Scene Description File
// File: grasspatch.inc
// Vers: 1.0 of grasspatch.inc for POV-Ray 3.1
// Desc: Draws a patch of grass based on a few simple variables
// Include at the beginning of the file
// Date: 01/18/2000
// Auth: Josh English
#declare HelloGrassPatch = true;
#ifndef(HelloBezier) #include "bezier.inc" #end
#macro DrawBlade(s1,s2,s3)
ConnectSmooth(s1,s2)
ConnectSmooth(s1,s3)
#end
#macro RangedRand(mn,mx,sv)
mn + rand(sv)*(mx-mn)
#end
#declare Blade_Tex = texture { pigment { rgb <0,0.3,0> } finish { phong 0.25 ambient 0.2 } }
#declare Blade_Height_Minimum = 1.75;
#declare Blade_Height_Maximum = 3;
// New on 1-22
#declare Blade_Detail = 10;
#declare Max_Blade_Angle = 45;
#declare Min_Blade_Angle = 10;
// until here
#declare someseed = seed(2345);
#declare xseed = seed(42);
#declare zseed = seed(369);
#declare Blade_Density = 2; // per unit
#declare Patch_Rotation = 0;
#declare Patch_Translation = <0,0,0>;
#declare Patch_Shape = 1; // 0 for circle, 1 for square, 2 for polygon
// used for PatchShape 0 (Circle)
#declare Clump_Radius_Minimum = 0;
#declare Clump_Radius_Maximum = 2;
// used for PatchShape 1 (Square)
#declare Patch_X_Minimum = -5;
#declare Patch_X_Maximum = 5;
#declare Patch_Z_Minimum = -5;
#declare Patch_Z_Maximum = 5;
// used for PatchShape 2 (Polygon)
#declare Patch_Sides = 3;
#declare Poly_Radius_Range = 0.333;
#declare RadialOffset = 0;
// used for PatchShape 3 (Curve)
#declare Patch_Path = array[4] { <-3,0,0>, <-1,0,5>, <1,0,-5> <3,0,0> }
#declare Path_Density = 6;
#declare Path_Points = 20;
#declare PlotPoints = false;
#declare Spread_Correction = 1;
#ifndef(NumberOfBlades) #declare NumberOfBlades = 100; #end
// New on 3-2-00
// This should allow us to make the blades further away less
// detailed, thus saving parse and render times
#declare Blade_Scale = 1;
#declare Blade_Width = 0.075;
#declare Use_Blade_Distance = false;
#declare Camera_Position = <0,0,-4>;
#declare Max_Blade_Detail = 20;
#declare Min_Blade_Detail = 5;
#declare Max_Detail_Distance = 1;
#declare Min_Detail_Distance = 10;
#macro FillOutBlade(A)
#local cpnt = vrotate(<Blade_Width,0,0>,<0,45,0>);
#local ccpnt = vrotate(<Blade_Width,0,0>,<0,-45,0>);
#declare ClockwiseSpline = array[4] { A[0] + cpnt,
A[1] + cpnt,
A[2] + <-0.1,0,-.1>,
A[3] + <0,0,-0.01> }
#declare CounterSpline = array[4] { A[0] + ccpnt,
A[1] + ccpnt,
A[2] + <-0.1,0,0.1>,
A[3] + <0,0,0.01> }
#end
// From MyMaxs
#macro Return(sd,ed,sr,er,rd,dg)
#local a = (rd - sd)/(ed-sd);
#local a = pow(a,dg);
#local b = sr + a*(er-sr);
max(min(b,er),sr)
#end
// the big macro
#macro PlantPatch()
#declare Temp_Number = NumberofPoints;
#declare NumberofPoints = Blade_Detail;
#declare Blade_Count = 0;
#declare Clump_Radius_Range = Clump_Radius_Maximum - Clump_Radius_Minimum;
#declare Blade_X_Range = Patch_X_Maximum - Patch_X_Minimum;
#declare Blade_Z_Range = Patch_Z_Maximum - Patch_Z_Minimum;
#declare Blade_Distance = 1/Blade_Density;
#declare X_Start = Patch_X_Minimum + 0.5*Blade_Distance;
#declare Z_Start = Patch_Z_Minimum + 0.5*Blade_Distance;
// Find how many blades to use
#switch(Patch_Shape)
#case(1) // Square
#declare NumberOfBlades = Blade_Density * Blade_X_Range * Blade_Density * Blade_Z_Range;
#break
#case(3) // Curve
#declare NumberOfBlades = Path_Points * Path_Density;
#break
#else
#declare NumberOfBlades = pow(Blade_Density,2) * int(pi*(pow(Clump_Radius_Maximum,2) - pow(Clump_Radius_Minimum,2)));
#end
#declare X_Count = X_Start;
#declare Z_Count = Z_Start;
#declare thisStop = 0;
#declare thisCycle = 1;
#declare BezTex = Blade_Tex
// #debug concat("\nX_range is " + str(Blade_X_Range,3,3))
// #debug concat("\nZ_range is " + str(Blade_Z_Range,3,3))
#debug concat("\nTotal number of dots is " , str(NumberOfBlades,3,0))
#while (Blade_Count < NumberOfBlades)
// Find the placement of the blade
#switch(Patch_Shape)
#case (1) // Square shape
#declare px = X_Count + rand(xseed)*2*Blade_Distance - Blade_Distance;
#declare pz = Z_Count + rand(zseed)*2*Blade_Distance - Blade_Distance;
#if ( px > Patch_X_Maximum ) #declare px = Patch_X_Maximum; #end
#if ( px < Patch_X_Minimum ) #declare px = Patch_X_Minimum; #end
#if ( pz > Patch_Z_Maximum ) #declare pz = Patch_Z_Maximum; #end
#if ( pz < Patch_Z_Minimum ) #declare pz = Patch_Z_Minimum; #end
#declare X_Count = X_Count + Blade_Distance;
#break
#case(2) // Polygon
// Step one find a random angle
#declare thisAngle = rand(someseed) *360;
// Step two find the maximum radius
#declare tempRadRAnge = Poly_Radius_Range*Clump_Radius_Maximum;
#declare thisMaxRadius = Clump_Radius_Maximum - abs(sin(thisAngle/360*pi*Patch_Sides))*tempRadRAnge;
// Step three find a random radius
#declare thisRadius = pow(rand(someseed),Spread_Correction)*thisMaxRadius;
#declare thisPoint = vrotate(<thisRadius,0,0>,<0,(thisAngle+RadialOffset),0>);
#declare px = thisPoint.x;
#declare pz = thisPoint.z;
#break
#case(3) //Curve
#declare thisCenter = ReturnPosition(Patch_Path,thisStop);
#declare thisRadius = pow(rand(someseed),Spread_Correction);
#declare thisPoint = <thisRadius*Clump_Radius_Maximum,0,0>;
#declare thisPoint = vrotate(thisPoint,<0,rand(someseed)*360,0>);
#declare thisPoint = thisPoint + thisCenter;
#declare px = thisPoint.x;
#declare pz = thisPoint.z;
#declare thisCycle = thisCycle + 1;
#break
#else // circular
#declare subr = pow(rand(someseed),Spread_Correction);
#declare subr = Clump_Radius_Minimum + subr*Clump_Radius_Range;
#declare thispoint = <subr,0,0>;
#declare thispoint = vrotate(thispoint,<0,rand(someseed)*360,0>);
#declare px = thispoint.x;
#declare pz = thispoint.z;
#end
// Create the Blade
#local h4 = RangedRand(Blade_Height_Minimum,Blade_Height_Maximum,someseed);
#local r4 = RangedRand(tan(radians(Min_Blade_Angle))*h4,tan(radians(Max_Blade_Angle))*h4,someseed);
#local curve = RangedRand(0.667,1.333,someseed);
#declare CentralSpline = array[4] { <0,0,0> <0,h4/3,0> <0,curve*h4,0> <r4,h4,0> }
FillOutBlade(CentralSpline)
#if (PlotPoints)
sphere { <px,0,pz> 0.25 texture {BezTex}
scale Blade_Scale translate Patch_Translation}
#else
// calculate detail (if necessary)
#if (Use_Blade_Distance)
#local Distance = vlength((<px,0,pz>+Patch_Translation)-Camera_Position);
#declare NumberofPoints = Return(Max_Detail_Distance,Min_Detail_Distance,Max_Blade_Detail,Min_Blade_Detail,Distance,1);
// #degub concat("\nDistance is " + str(Distance,3,3))
// #debug concat(" Number of Points is " + str(NumberofPoints,3,3))
#end
union { DrawBlade(CentralSpline,ClockwiseSpline,CounterSpline)
rotate rand(someseed)*360*y
scale Blade_Scale
translate<px,0,pz>+Patch_Translation }
#end
// Reset X_Count and Z_Count if necessary
#if (X_Count > Patch_X_Maximum)
#declare Z_Count = Z_Count + Blade_Distance;
#declare X_Count = X_Start;
#end
// Reset thisStop and thisCycle if necessary
#if ( thisCycle > Path_Density )
#declare thisStop = thisStop + (1/Path_Points);
#declare thisCycle = 1;
#end
#declare Blade_Count = Blade_Count + 1;
#end
#declare NumberofPoints = Temp_Number;
#end