#declare EarthTexture = texture{ T_brown3 scale 5.5 };

#declare ForestEarthHighness = SlopesHeight - 0.1;

#declare ForestCornerStart = < NorthEastCorner.x, ForestEarthHighness, NorthEastCorner.z >;
#declare ForestCornerEnd = < WestSlopesXCoord, 0, NorthEastCorner.z + 400 >;

#declare NorthForestEarthBox =
box{ ForestCornerStart, ForestCornerEnd texture{ EarthTexture } }

#declare TreesPlacingNoise = seed( 1024 );
#declare PlantsPlacingNoise = seed( 2048 );
#declare PlantsTransformSeed = seed( 4096 );
#declare KapokTreesScaleSeed = seed( 8192 );
#declare TreeChoiceSeed = seed( 79231 );
#declare TreesSpacingDist = 8;
#declare PlantsSpacingDist = 1.5;

#if( PlaceFlore )
	#declare TreesArray = array[2]{ KapokTree1, KapokTree2 }
#end

#declare KapokTreesScale = 10;

#macro RecordTreesPlantingLocation(PlantingSurface, BorderSpacing, TreesRecordArray, TreesSpacing, TreesNoise)
	#local RecordArrayIndex = 0;
	#for( ItX, min_extent( PlantingSurface ).x + BorderSpacing, max_extent( PlantingSurface ).x - BorderSpacing, TreesSpacing )
		#for( ItZ, min_extent( PlantingSurface ).z + BorderSpacing, max_extent( PlantingSurface ).z - BorderSpacing, TreesSpacing )
			#local Coord = < ItX + SetWithAffineFunction( 0, 1, -TreesSpacing / 4, TreesSpacing / 4, rand(TreesNoise) ), 
							max_extent( PlantingSurface ).y , 
							ItZ + SetWithAffineFunction( 0, 1, -TreesSpacing / 4, TreesSpacing / 4, rand(TreesNoise) )
							>;
			DoubleArraySizeIfNeeded( TreesRecordArray, RecordArrayIndex )
			#ifndef( TreesRecordArray[RecordArrayIndex] )
				#declare TreesRecordArray[RecordArrayIndex] = Coord;
				#local RecordArrayIndex = RecordArrayIndex + 1;
			#else
				#error "Index with defined array elements in 'RecordTreesPlantingLocation' macro\n"
			#end
		#end
	#end
	Resize_Array( TreesRecordArray, RecordArrayIndex )
#end

#macro HasPlantNoTreeNearIt(TreesRecordArray, PlantLocation, PlantSpaceMinimum)
	#local CanPlacePlant = 1;
	#for( TreeLocation, 0, dimension_size( TreesRecordArray, 1 ) - 1 )
		#if( VDist( PlantLocation, TreeLocation ) < PlantSpaceMinimum )
			#local CanPlacePlant = 0;
		#end
	#end
	CanPlacePlant
#end

#macro RecordPlantsLocationAmongTrees(PlantingSurface, BorderSpacing, TreesRecordArray, PlantsRecordArray, PlantsSpacing, PlantsNoiseRand)
	#local RecordPlantsArrayIndex = 0;
	#for( ItX, min_extent( PlantingSurface ).x + BorderSpacing, max_extent( PlantingSurface ).x - BorderSpacing, PlantsSpacing )
		#for( ItZ, min_extent( PlantingSurface ).z + BorderSpacing, max_extent( PlantingSurface ).z - BorderSpacing, PlantsSpacing )
			#local NewPlantLocation = < ItX + SetWithAffineFunction( 0, 1, -PlantsSpacing / 3, PlantsSpacing / 3, rand(PlantsNoiseRand) )
								max_extent( PlantingSurface ).y, 
								ItZ + SetWithAffineFunction( 0, 1, -PlantsSpacing / 4, PlantsSpacing / 4, rand(PlantsNoiseRand) )
								>;
			#if( HasPlantNoTreeNearIt(TreesRecordArray, NewPlantLocation, PlantsSpacing ) = 1 )
				DoubleArraySizeIfNeeded( PlantsRecordArray, RecordPlantsArrayIndex )
				#ifndef( PlantsRecordArray[RecordPlantsArrayIndex] )
					#declare PlantsRecordArray[RecordPlantsArrayIndex] = NewPlantLocation;
					#local RecordPlantsArrayIndex = RecordPlantsArrayIndex + 1;
				#else
					#error "Index with defined array elements in 'RecordPlantsLocationAmongTrees' macro\n"
				#end
			#end
		#end
	#end
	Resize_Array( PlantsRecordArray, RecordPlantsArrayIndex )
#end

#macro PlacePlants(LocationsArray, ObjectToPlant, ScaleSeed, RotateSeed)
	#for( It, 0, dimension_size( LocationsArray, 1 ) - 1 )
		object{ ObjectToPlant 
			scale SetWithAffineFunction( 0, 1, 0.85, 1.1, rand(ScaleSeed) ) 
			rotate < 0, SetWithAffineFunction( 0, 1, 0, 360, rand(RotateSeed) ), 0 >
			translate LocationsArray[It] 
		}
	#end
#end

#macro PlaceTrees(LocationsArray, ObjectsArray, TreeHighnessSeed, ObjectsChoiceSeed )
	#for( It, 0, dimension_size( LocationsArray, 1 ) - 1 )
		#local ArrayIndex = SetWithAffineFunction( 0, 1, 0, dimension_size( ObjectsArray, 1 ) - 1, rand( ObjectsChoiceSeed ) );
		object{ ObjectsArray[ArrayIndex]
			scale SetWithAffineFunction( 0, 1, KapokTreesScale, KapokTreesScale * 1.6, rand(TreeHighnessSeed) )
			rotate < 0, SetWithAffineFunction( 0, 1, 0, 360, rand(TreeHighnessSeed) ), 0 >
			translate LocationsArray[It] }
	#end
#end

#macro PlantForest(PlantingSurface, BlockName)
	#debug concat( "Planting flore background for ", BlockName, ".\n" )
	ObjectSizeCout( PlantingSurface, "ForestBox" )
	
	#local TreesLocationArray = array[100];
	#local PlantsLocationArray = array[100];
	
	#debug "Start trees searching location macro\n"
	RecordTreesPlantingLocation( PlantingSurface, 7, TreesLocationArray, TreesSpacingDist, TreesPlacingNoise)
	DisplayValueInConsole( dimension_size( TreesLocationArray, 1 ), "TreesNumber")
	
	#debug "Start plants searching location macro\n"
	RecordPlantsLocationAmongTrees( PlantingSurface, 1.5, TreesLocationArray, PlantsLocationArray, PlantsSpacingDist, PlantsPlacingNoise )
	DisplayValueInConsole( dimension_size( PlantsLocationArray, 1 ), "PlantsNumber")
	
	PlaceTrees( TreesLocationArray, TreesArray, KapokTreesScaleSeed, TreeChoiceSeed )
	PlacePlants( PlantsLocationArray, Plant1_Object, PlantsTransformSeed, PlantsTransformSeed )
#end

#declare SideWalkWidth = 1;
#declare SideWalkDepth = max_extent( NorthForestEarthBox ).z - PtE.z;
#declare SideWalkHighness = SideWalkWidth / 4;
#declare PigmentVarPercent = ( SideWalkWidth - SideWalkHighness / 2 ) / SideWalkWidth * 0.8;
#declare Yellow = color srgb < 1, 1, 0 >;
#declare SideWalkGray = color srgb 0.7;

#declare SideWalkPrism =
prism{ linear_sweep linear_spline 0, -SideWalkDepth, 6,
	< 0, 0 >, 
	< SideWalkWidth, 0 >, 
	< SideWalkWidth, SideWalkHighness / 2 >, 
	< SideWalkWidth - SideWalkHighness / 2, SideWalkHighness >, 
	< 0, SideWalkHighness >, 
	< 0, 0 >
	texture{ 
		pigment{ gradient x color_map{ [ 0 SideWalkGray ][ PigmentVarPercent SideWalkGray ][ PigmentVarPercent Yellow ] } 
					scale < SideWalkWidth, 1, 1 > }
		normal{ bumps 0.15 scale 0.025 }
	}
	rotate -90 * x
}

#declare SideWalkSize = max_extent( SideWalkPrism ) - min_extent( SideWalkPrism );

#declare EastSideRoadScale = < 8, 0.025, ForestCornerEnd.z - SouthSlopesZCoord >;
#declare CrackleSubScale = 0.15;

#declare RoadLineWidth = 0.018;
#declare White = color srgb 1;
#declare WhiteLinePigment = pigment{ gradient z color_map{ [0.8 White][0.8 color srgbt 1 ] } }

#declare RoadWhiteLine =
texture{ 
	pigment{ 
		gradient x pigment_map{ 
			[ 0.5 - RoadLineWidth color srgbt 1 ]
			[ 0.5 - RoadLineWidth WhiteLinePigment ]
			[ 0.5 + RoadLineWidth WhiteLinePigment ]
			[ 0.5 + RoadLineWidth color srgbt 1 ]
		}
	}
}

#declare EastSideRoad =
height_field{
	function 2048, 2048{ pigment{ crackle scale < 1 / EastSideRoadScale.x, 1 / EastSideRoadScale.z, 1 > 
											* < CrackleSubScale, CrackleSubScale, 1 > } }
	smooth
	texture{ pigment{ color srgb < 0.385, 0.385, 0.4 > } }
	texture{ RoadWhiteLine scale < 1, 1, 0.025 > }
	
	scale EastSideRoadScale
	translate < NorthEastCorner.x + SideWalkSize.x, PtE.y - SideWalkSize.y , PtE.z >
}

#declare RightSideRoadConcreteBlock =
box{ < max_extent( EastSideRoad ).x + SideWalkSize.x, 0, max_extent( EastSideRoad ).z >,
	< max_extent( EastSideRoad ).x + SideWalkSize.x + NorthEastCorner.x - SlopesWidth, SlopesHeight, SouthSlopesZCoord > 
	texture{ ConcreteTexture }
}

#declare EastForestEarthBox =
box{ < max_extent( RightSideRoadConcreteBlock ).x, 0, min_extent(EastSideRoad).z >,
	< max_extent( RightSideRoadConcreteBlock ).x + 100, ForestEarthHighness, max_extent(EastSideRoad).z >
	texture{ EarthTexture }
}