//Macro to generate a whole forest
//Boundaries of the forest: z is from 40 (camp end) to 1280 (start of first mountain) x is from -1536 to 1664 

#include "math.inc"

#declare ForestMin = <-1536, 0, 30>;
#declare ForestMax = <1664, 0, 1280>;
#declare FloreSquareWidth = 25;

#declare LittleFlorePlaceRadius = <3, 0, 3>;
#declare LittleFloreChoice = seed(1234);
#declare LittleFloreYRotate = seed(789);
#declare LF_PosNoise = seed(34000);
#declare LFLowNoise = 0.25;
#declare LFHighNoise = 0.55;

#declare GreatTreeChoice = seed(655);
#declare GreatTreeYRotate = seed(79230);
#declare GreatTreePositionSeed = seed(5679);//5678
#declare TreeLowNoise = 2;
#declare TreeHighNoise = 4;
#declare GreatTreesTrunkRadius = 3;
#declare ScaleNoiseSeed = seed(14110);
#declare ScaleNoiseAdded = 4;
#declare GrassBladeRandPos = seed(6123);


#macro GetTwoIntervalsNumber( RandomNumber, LowExpectedValue, HighExpectedValue )
	#if( RandomNumber >= 0 & RandomNumber <= 0.5)
		(HighExpectedValue - LowExpectedValue) / 0.5 * RandomNumber + LowExpectedValue 
	#else
		( LowExpectedValue  * ( 0.5 - RandomNumber ) + HighExpectedValue * ( RandomNumber - 1) ) / 0.5
	#end
#end

#macro PlaceGreatTree( GreatTreeNumber, TreeYRotate, Position, AddedScale)
	#local AddPos = < GetTwoIntervalsNumber(rand(GreatTreePositionSeed), TreeLowNoise, TreeHighNoise) , 0, GetTwoIntervalsNumber(rand(GreatTreePositionSeed), TreeLowNoise, TreeHighNoise) >; 
	
	#if( GreatTreeNumber >= 0 & GreatTreeNumber < 0.333 )
		#if( GreatTreeNumber >= 0 & GreatTreeNumber < 0.018 )
			PlaceObject(KapokTree1, KapokTreeScale + rand(ScaleNoiseSeed) * ScaleNoiseAdded + AddedScale + 28, TreeYRotate, Position + AddPos )
		#else
			PlaceObject(KapokTree1, KapokTreeScale + rand(ScaleNoiseSeed) * ScaleNoiseAdded + AddedScale, TreeYRotate, Position + AddPos )
		#end
	#elseif( GreatTreeNumber >= 0.333 & GreatTreeNumber < 0.666 )
		#if( GreatTreeNumber >= 0.333 & GreatTreeNumber < 0.35 )
			PlaceObject(KapokTree2, KapokTreeScale + rand(ScaleNoiseSeed) * ScaleNoiseAdded + AddedScale + 24, TreeYRotate, Position + AddPos )
		#else
			PlaceObject(KapokTree2, KapokTreeScale + rand(ScaleNoiseSeed) * ScaleNoiseAdded + AddedScale, TreeYRotate, Position + AddPos )
		#end
	#else
		PlaceObject(WavedBranches, WavedBranchesScale + rand(ScaleNoiseSeed) * ScaleNoiseAdded + AddedScale, TreeYRotate, Position)
	#end
#end

#macro PlaceLittleFlore(FloreChoice, YFloreRotation, Position)
	#if( FloreChoice >= 0 & FloreChoice < 1/6 )
		PlaceObject( Bush1, BushScale, YFloreRotation, Position )
	#elseif( FloreChoice >= 1/6 & FloreChoice < 2/6 )
		PlaceObject( Colibri, ColibriScale, YFloreRotation, Position )
	#elseif( FloreChoice >= 2/6 & FloreChoice < 3/6 )
		PlaceObject( FlatLeavesPour, FlatLeavesPourScale, YFloreRotation, Position )
	#elseif( FloreChoice >= 3/6 & FloreChoice < 4/6 )
		PlaceObject( FlatLeavesUpright, FlatLeavesUprightScale, YFloreRotation, Position )
	#elseif( FloreChoice >= 4/6 & FloreChoice < 5/6 )
		PlaceObject( GreenPlant, GreenPlantScale, YFloreRotation, Position )
	#else
		PlaceObject( LittleFlore, LittleFloreScale, YFloreRotation, Position )
	#end
#end

#macro IsInsideBoundaries(ObjectPosition, BoundsCenter)
	ObjectPosition.z >= BoundsCenter.z - LittleFlorePlaceRadius.z
	& ObjectPosition.z < BoundsCenter.z + LittleFlorePlaceRadius.z
	& ObjectPosition.x >= BoundsCenter.x - LittleFlorePlaceRadius.x
	& ObjectPosition.x < BoundsCenter.x + LittleFlorePlaceRadius.x
#end

#macro RecordPosition(PositionsArray, PositionsArrayIndex, NewPositionVector)
	DoubleArraySizeIfNeeded( PositionsArray, PositionsArrayIndex )
	#declare PositionsArray[PositionsArrayIndex] = NewPositionVector;
	#declare PositionsArrayIndex = PositionsArrayIndex + 1;
#end

#macro LoopLittleFlore(SecondTreePosition, GreatTreePosition, LittleFloreNum, PositionsArray, PositionsArrayIndex, RecordStatusBool)
	#for( Z_pos, SecondTreePosition.z, SecondTreePosition.z + FloreSquareWidth - LittleFlorePlaceRadius.z, LittleFlorePlaceRadius.z )
		#for( X_pos, SecondTreePosition.x, SecondTreePosition.x + FloreSquareWidth - LittleFlorePlaceRadius.x, LittleFlorePlaceRadius.x )
			#local LittleFlorePosition = <X_pos + GetTwoIntervalsNumber( rand(LF_PosNoise), LFLowNoise, LFHighNoise), 
											0, 
											Z_pos + GetTwoIntervalsNumber( rand(LF_PosNoise), LFLowNoise, LFHighNoise) >;
			#if( !(IsInsideBoundaries( LittleFlorePosition, GreatTreePosition ) | IsInsideBoundaries( LittleFlorePosition, SecondTreePosition ) ) )
				PlaceLittleFlore(rand(LittleFloreChoice), 360 * rand(LittleFloreYRotate), LittleFlorePosition )
				#local LittleFloreNum = LittleFloreNum + 1;
				#if( RecordStatusBool )
					RecordPosition(PositionsArray, PositionsArrayIndex, LittleFlorePosition)
				#end
			#end
		#end
	#end
#end

#macro LoopOverSquares(MinVector, MaxVector, GreatTreesNumber, LittleFloreNum, PositionsArray, PositionsArrayIndex, RecordStatusBool)
	#for( Z_Pos, MinVector.z, MaxVector.z, FloreSquareWidth)
		#for( X_Pos, MinVector.x, MaxVector.x, FloreSquareWidth)
			#local GreatTreePos = < X_Pos + FloreSquareWidth / 2, 0, Z_Pos + FloreSquareWidth / 2>;
			#local SecondTreePos = < X_Pos, 0, Z_Pos >;
			PlaceGreatTree(rand(GreatTreeChoice), 360*rand(GreatTreeYRotate), SecondTreePos, SetWithAffineFunction(0, 1400, 0, 24, Z_Pos ) )
			PlaceGreatTree(rand(GreatTreeChoice), 360*rand(GreatTreeYRotate), GreatTreePos, SetWithAffineFunction(0, 1400, 0, 24, Z_Pos ) )
			LoopLittleFlore(SecondTreePos, GreatTreePos, LittleFloreNum, PositionsArray, PositionsArrayIndex, RecordStatusBool )
			#local GreatTreesNumber = GreatTreesNumber + 2;
		#end
	#end
#end

//Below: place little flore around Birch at the foreground on the right
#macro IsOneObjectNear(ObjectsPosArray, LocalRadius, LittleFlorePos)
	#local NearObjects = 0;
	#for( It, 0, dimension_size( ObjectsPosArray, 1 ) - 1 )
		#ifdef( ObjectsPosArray[It] )
			#if(  LittleFlorePos.x >= ObjectsPosArray[It].x - LocalRadius.x
				& LittleFlorePos.x <  ObjectsPosArray[It].x + LocalRadius.x
				& LittleFlorePos.z >= ObjectsPosArray[It].z - LocalRadius.z
				& LittleFlorePos.z <  ObjectsPosArray[It].z + LocalRadius.z )
				#local NearObjects = NearObjects + 1;
			#end
		#end
	#end
	NearObjects
#end

//Boundaries are -14, 0 on z and 32 , 132 on x
#macro PlaceLittleFloreAroundObject(ObjectsPosArray, StartPos, EndPos, LittleFloreNum, LocalRadius, PositionsArray, PositionsArrayIndex)
	#for( X_Pos, StartPos.x, EndPos.x, LittleFlorePlaceRadius.x )
		#for( Z_Pos, StartPos.z, EndPos.z, LittleFlorePlaceRadius.z )
			#local LittleFlorePosition = < X_Pos + GetTwoIntervalsNumber( rand(LF_PosNoise), LFLowNoise, LFHighNoise), 
											0, 
											Z_Pos + GetTwoIntervalsNumber( rand(LF_PosNoise), LFLowNoise, LFHighNoise) >;
			#if( 0 = IsOneObjectNear(ObjectsPosArray, LocalRadius, LittleFlorePosition) )
				PlaceLittleFlore(rand(LittleFloreChoice), 360 * rand(LittleFloreYRotate), LittleFlorePosition )
				#declare LittleFloreNum = LittleFloreNum + 1;
				RecordPosition(PositionsArray, PositionsArrayIndex, LittleFlorePosition)
			#end
		#end
	#end
#end

#macro DebugEmptyArray(PositionsArray)
	#if( dimension_size(PositionsArray, 1 ) = 0 )
		#error "PositionsArray array size is equal to 0, can't carry on. Location: 'PlaceGrassBladeAroundLittleFlore(' macro .\n"
	#end
#end

#macro PlaceGrassBladeAroundLittleFlore(PositionsArray, MinDistance, MaxDistance, SpacingDistance)
	#debug "Placing grass blade around little flore.\n"
	//Conditions to plant grass blade are:
	//	- Close enough to a little flore
	//	- Not too far from everything ( must be tested with all positions )
	
	#local GrassBladeCount = 0;
	#for( ItX, min_extent(GrassBladeGround).x, max_extent(GrassBladeGround).x, SpacingDistance )
		#for( ItZ, min_extent(GrassBladeGround).z, max_extent(GrassBladeGround).z, SpacingDistance )
			#local XNoise = SetWithAffineFunction( 0, 1, -SpacingDistance / 3, SpacingDistance / 3, rand( GrassBladeRandPos ) );
			#local ZNoise = SetWithAffineFunction( 0, 1, -SpacingDistance / 3, SpacingDistance / 3, rand( GrassBladeRandPos ) );
			#local FinalCoords = < ItX + XNoise, 0, ItZ + ZNoise >;
			#local TooClosed = false;
			#local IsTooFarFromEverything = true;
			#local PositionIndex = 0;
			#local ContinueWhileLoop = true;
			#while( ContinueWhileLoop & PositionIndex < dimension_size( PositionsArray, 1 ) - 1 & !( TooClosed ) )
				#ifdef( PositionsArray[PositionIndex] )
					#local Distance = VDist( PositionsArray[PositionIndex], FinalCoords );
					#if( Distance < MinDistance )
						#local TooClosed = true;
					#end
					#if( Distance <= MaxDistance )
						#local IsTooFarFromEverything = false;
					#end
				#else
					#local ContinueWhileLoop = false;
				#end
				#local PositionIndex = PositionIndex + 1;
			#end
			#if( !( TooClosed ) & !( IsTooFarFromEverything ) )
				CreatePlant1(FinalCoords + < 0, Y_Ground, 0 >)
				#local GrassBladeCount = GrassBladeCount + 1;
			#end
		#end
	#end
	#debug concat("Placed ", str( GrassBladeCount, 0, 0 ), " grass blades near little flore.\n")
#end