/// <summary>
        /// Get the total number of unique stencil layers of a given resolution within a list of LBFilter.
        /// NOTE: Assumes that stencil, stencilLayer and stencilLayerResolution has already been cached in the LBFilter.
        /// </summary>
        /// <param name="lbFilterList"></param>
        /// <param name="resolution"></param>
        /// <returns></returns>
        public static int GetNumStencilLayersByResolution(List <LBFilter> lbFilterList, int resolution)
        {
            int      numUniqueLayers = 0;
            LBFilter lbFilter        = null;

            int numLBFilters = lbFilterList == null ? 0 : lbFilterList.Count;

            if (numLBFilters > 0)
            {
                // Create with some initial capacity
                List <string> stencilLayerGUIDList = new List <string>(10);

                for (int fIdx = 0; fIdx < numLBFilters; fIdx++)
                {
                    lbFilter = lbFilterList[fIdx];

                    // Is this a valid stencil layer with the correct resolution?
                    if (lbFilter != null && lbFilter.filterType == LBFilter.FilterType.StencilLayer && !string.IsNullOrEmpty(lbFilter.lbStencilGUID) && !string.IsNullOrEmpty(lbFilter.lbStencilLayerGUID) && lbFilter.stencilLayerResolution == resolution)
                    {
                        //Debug.Log("[DEBUG] GetNumStencilLayersByResolution " + lbFilter.lbStencilLayer.LayerName + " " + lbFilter.stencilLayerResolution + " GUID: " + lbFilter.lbStencilLayerGUID + " " + lbFilter.lbStencilLayer.GUID);

                        // If it doesn't already exist, add it to the list of unique Stencil Layer GUIDs
                        if (!stencilLayerGUIDList.Exists(guid => guid == lbFilter.lbStencilLayerGUID))
                        {
                            numUniqueLayers++;
                            stencilLayerGUIDList.Add(lbFilter.lbStencilLayerGUID);
                            //Debug.Log(" [DEBUG] GetNumStencilLayersByResolution - Adding " + lbFilter.lbStencilLayerGUID + " resolution: " + resolution);
                        }
                    }
                }
            }

            return(numUniqueLayers);
        }
Beispiel #2
0
        /// <summary>
        /// Preload the stencils for ALL groups
        /// </summary>
        public void PreloadStencilData()
        {
            isStencilLayerFiltersToApply = new bool[numActiveGroups];

            for (int i = 0; i < numActiveGroups; i++)
            {
                // Are there any Stencil Layer filters for this group?
                isStencilLayerFiltersToApply[i] = LBFilter.Contains(activeGroupList[i].filterList, LBFilter.FilterType.StencilLayer);
                if (isStencilLayerFiltersToApply[i])
                {
                    // Preload the stencil data
                    if (activeGroupList[i].filterList != null)
                    {
                        foreach (LBFilter lbFilter in activeGroupList[i].filterList)
                        {
                            if (lbFilter != null)
                            {
                                // Currently all stencil filters are AND
                                // Is this a valid Stencil Filter?
                                if (lbFilter.filterType == LBFilter.FilterType.StencilLayer && !string.IsNullOrEmpty(lbFilter.lbStencilGUID) && !string.IsNullOrEmpty(lbFilter.lbStencilLayerGUID))
                                {
                                    // If the temporary class instance isn't defined, look it up and validate it is in the current landscape
                                    if (lbFilter.lbStencil == null)
                                    {
                                        lbFilter.lbStencil = LBStencil.GetStencilInLandscape(lbGroupParams.landscape, lbFilter.lbStencilGUID, lbGroupParams.showErrors);
                                    }

                                    if (lbFilter.lbStencil != null)
                                    {
                                        // Find the Stencil Layer for this Layer Filter and populate the temporary class instance
                                        lbFilter.lbStencilLayer = lbFilter.lbStencil.GetStencilLayerByGUID(lbFilter.lbStencilLayerGUID);

                                        // Load the USHORT data
                                        if (lbFilter.lbStencilLayer != null)
                                        {
                                            if (lbFilter.lbStencilLayer.layerArray == null)
                                            {
                                                lbFilter.lbStencilLayer.AllocLayerArray();
                                                lbFilter.lbStencilLayer.UnCompressToUShort();
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // Stencil LBLayerFilter temp variables
            stencilLayerPosN = new Vector2();
        }
Beispiel #3
0
 /// <summary>
 /// Constructor to create a clone of a LBFilter instance
 /// </summary>
 /// <param name="lbFilter"></param>
 public LBFilter(LBFilter lbFilter)
 {
     this.filterType          = lbFilter.filterType;
     this.filterMode          = lbFilter.filterMode;
     this.areaRect            = lbFilter.areaRect;
     this.showAreaHighlighter = lbFilter.showAreaHighlighter;
     this.minProximity        = lbFilter.minProximity;
     this.layerMask           = lbFilter.layerMask;
     this.filterByTag         = lbFilter.filterByTag;
     this.terrainTexture      = new LBTerrainTexture(lbFilter.terrainTexture);
     this.lbStencilGUID       = lbFilter.lbStencilGUID;
     this.lbStencilLayerGUID  = lbFilter.lbStencilLayerGUID;
     this.lbBiome             = lbFilter.lbBiome;
     this.cutOff = lbFilter.cutOff;
 }
Beispiel #4
0
 /// <summary>
 /// Find the first LBTerrainTexture that has the same GUID or Texture2D image as the Texture filter.
 /// Update the filter. NOTE: If there are multiple uses of the same texture, this may sometimes
 /// get the wrong texture. The only way to correct this is to fully populate the LBFilter will
 /// all the LBTerrainTexture attributes (like Normalmap, smoothness, metallic etc).
 /// </summary>
 /// <param name="lbFilterList"></param>
 /// <param name="lbTerrainTextureList"></param>
 public static void UpdateTextures(List <LBFilter> lbFilterList, List <LBTerrainTexture> lbTerrainTextureList, bool showErrors)
 {
     if (lbTerrainTextureList == null)
     {
         if (showErrors)
         {
             Debug.LogWarning("ERROR LBFilter.UpdateTextures - List of available textures cannot be null");
         }
     }
     else if (lbTerrainTextureList.Count < 1)
     {
         if (showErrors)
         {
             Debug.Log("INFO LBFilter.UpdateTextures - List of available textures is empty");
         }
     }
     else if (lbFilterList != null)
     {
         for (int f = 0; f < lbFilterList.Count; f++)
         {
             LBFilter lbFilter = lbFilterList[f];
             if (lbFilter != null)
             {
                 if (lbFilter.filterType == FilterType.Texture)
                 {
                     // Find the first matching texture using GUID or only the Texture2D image. NOTE: this may be incorrect for
                     // landscapes with the same Texture2D used multiple times in the Texturing tab.
                     // Before LB 2.3.2 GUID may have been incorrect.
                     int textureIndex = lbTerrainTextureList.FindIndex(ftx => (!string.IsNullOrEmpty(lbFilter.terrainTexture.GUID) && ftx.GUID == lbFilter.terrainTexture.GUID) || ftx.texture == lbFilter.terrainTexture.texture);
                     if (textureIndex >= 0)
                     {
                         //Debug.Log("UpdateTextures Found: " + lbFilter.terrainTexture.texture.name);
                         lbFilter.terrainTexture = new LBTerrainTexture(lbTerrainTextureList[textureIndex]);
                         // Set the GUID to the original terrainTexture GUID
                         lbFilter.terrainTexture.GUID = lbTerrainTextureList[textureIndex].GUID;
                     }
                     else
                     {
                         if (showErrors)
                         {
                             Debug.LogWarning("ERROR LBFilter.UpdateTextures - could not find a match for " + (lbFilter.terrainTexture != null && lbFilter.terrainTexture.texture != null ? lbFilter.terrainTexture.texture.name : "filter " + (f + 1).ToString()));
                         }
                     }
                 }
             }
         }
     }
 }
Beispiel #5
0
        /// <summary>
        /// Create an LBFilter for Stencil Layer using the LBStencil instance and the name of the layer
        /// </summary>
        /// <param name="lbStencil"></param>
        /// <param name="layerName"></param>
        /// <param name="showErrors"></param>
        /// <returns></returns>
        public static LBFilter CreateFilter(LBStencil lbStencil, string layerName, bool showErrors)
        {
            LBFilter lbFilter = null;

            if (lbStencil == null)
            {
                if (showErrors)
                {
                    Debug.LogWarning("LBFilter.CreateFilter - stencil is null");
                }
            }
            else if (string.IsNullOrEmpty(layerName))
            {
                if (showErrors)
                {
                    Debug.LogWarning("LBFilter.CreateFilter - layerName is an empty string");
                }
            }
            else
            {
                lbFilter = new LBFilter(LBFilter.FilterType.StencilLayer, FilterMode.AND);
                if (lbFilter == null)
                {
                    if (showErrors)
                    {
                        Debug.LogWarning("LBFilter.CreateFilter - could not create LBFilter for " + lbStencil.stencilName + "." + layerName);
                    }
                }
                else
                {
                    lbFilter.lbStencilGUID = lbStencil.GUID;

                    // Find the new stencil layer
                    LBStencilLayer lbStencilLayer = lbStencil.GetStencilLayerByName(layerName);
                    if (lbStencilLayer != null)
                    {
                        lbFilter.lbStencilLayerGUID = lbStencilLayer.GUID;
                    }
                    else
                    {
                        lbFilter = null;
                    }
                }
            }

            return(lbFilter);
        }
Beispiel #6
0
        /// <summary>
        /// Create an LBFilter for Stencil Layer using the LBStencil instance GUID and the GUID of the stencil layer
        /// </summary>
        /// <param name="lbStencilGUID"></param>
        /// <param name="lbStencilLayerGUID"></param>
        /// <param name="showErrors"></param>
        /// <returns></returns>
        public static LBFilter CreateFilter(string lbStencilGUID, string lbStencilLayerGUID, bool showErrors)
        {
            LBFilter lbFilter = null;

            if (string.IsNullOrEmpty(lbStencilGUID))
            {
                if (showErrors)
                {
                    Debug.LogWarning("LBFilter.CreateFilter - lbStencilGUID is an empty string");
                }
            }
            else if (string.IsNullOrEmpty(lbStencilLayerGUID))
            {
                if (showErrors)
                {
                    Debug.LogWarning("LBFilter.CreateFilter - lbStencilLayerGUID is an empty string");
                }
            }
            else
            {
                lbFilter = new LBFilter(FilterType.StencilLayer, FilterMode.AND);
                if (lbFilter == null)
                {
                    if (showErrors)
                    {
                        Debug.LogWarning("LBFilter.CreateFilter - could not create LBFilter");
                    }
                }
                else
                {
                    lbFilter.lbStencilGUID      = lbStencilGUID;
                    lbFilter.lbStencilLayerGUID = lbStencilLayerGUID;
                }
            }

            return(lbFilter);
        }
        public string ScriptGrass(int GrassIdx, string EndOfLineMarker = "\n")
        {
            // Create a new instance of StringBuilder and give it an estimated capacity
            System.Text.StringBuilder sb = new System.Text.StringBuilder(1000);

            string eol = " ";

            // We always need a space between lines OR a end of line marker like "\n"
            if (EndOfLineMarker.Length > 0)
            {
                eol = EndOfLineMarker;
            }

            string grInst      = "lbTerrainGrass" + (GrassIdx + 1);
            string grInstAbrev = "Grs" + (GrassIdx + 1);

            sb.Append("// Grass Code generated from Landscape Builder 2 at " + System.DateTime.Now.ToShortTimeString() + " on " + System.DateTime.Now.ToLongDateString() + eol + eol);

            sb.Append("// BEGIN Public variables to populate in the editor - Uncomment and add these to top of class " + eol);
            sb.Append("//[Header(\"Grass" + (GrassIdx + 1) + "\")] " + eol);
            sb.Append("//public Texture2D texture" + grInstAbrev + "; " + eol);
            sb.Append("//public GameObject meshPrefab" + grInstAbrev + "; " + eol);
            sb.Append("//public Texture2D map" + grInstAbrev + "; " + eol);
            sb.Append("// END Public variables" + eol + eol);

            sb.Append("#region LBTerrainGrass" + (GrassIdx + 1) + eol);
            sb.Append("LBTerrainGrass " + grInst + " = new LBTerrainGrass(); " + eol);
            sb.Append("if (" + grInst + " != null)" + eol);
            sb.Append("{" + eol);
            sb.Append("\t" + grInst + ".texture = texture" + grInstAbrev + "; " + eol);
            sb.Append("\t" + grInst + ".textureName = " + (string.IsNullOrEmpty(textureName) ? "\"\"" : "\"" + textureName + "\"") + "; " + eol);
            sb.Append("\t" + grInst + ".minHeight = " + minHeight + "f; " + eol);
            sb.Append("\t" + grInst + ".maxHeight = " + maxHeight + "f; " + eol);
            sb.Append("\t" + grInst + ".minWidth = " + minHeight + "f; " + eol);
            sb.Append("\t" + grInst + ".maxWidth = " + maxHeight + "f; " + eol);
            sb.Append("\t" + grInst + ".healthyColour = new Color(" + healthyColour.r + "f," + healthyColour.g + "f," + healthyColour.b + "f," + healthyColour.a + "f); " + eol);
            sb.Append("\t" + grInst + ".dryColour = new Color(" + dryColour.r + "f," + dryColour.g + "f," + dryColour.b + "f," + dryColour.a + "f); " + eol);
            sb.Append("\t" + grInst + ".noiseSpread = " + noiseSpread + "f; " + eol);
            sb.Append("\t" + grInst + ".minPopulatedHeight = " + minPopulatedHeight + "f; " + eol);
            sb.Append("\t" + grInst + ".maxPopulatedHeight = " + maxPopulatedHeight + "f; " + eol);
            sb.Append("\t" + grInst + ".minInclination = " + minInclination + "f; " + eol);
            sb.Append("\t" + grInst + ".maxInclination = " + maxInclination + "f; " + eol);
            sb.Append("\t" + grInst + ".influence = " + influence + "f; " + eol);
            sb.Append("\t" + grInst + ".minDensity = " + minDensity + "; " + eol);
            sb.Append("\t" + grInst + ".density = " + density + "; " + eol);
            sb.Append("\t" + grInst + ".detailRenderMode = DetailRenderMode." + detailRenderMode + "; " + eol);
            sb.Append("\t" + grInst + ".grassPlacingMode = LBTerrainGrass.GrassPlacingMode." + grassPlacingMode + "; " + eol);
            sb.Append("\t" + grInst + ".grassPatchFadingMode = LBTerrainGrass.GrassPatchFadingMode." + grassPatchFadingMode + "; " + eol);
            sb.Append("\t" + grInst + ".isCurvatureConcave = " + isCurvatureConcave.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + grInst + ".curvatureDistance = " + curvatureDistance + "f; " + eol);
            sb.Append("\t" + grInst + ".curvatureMinHeightDiff = " + curvatureMinHeightDiff + "f; " + eol);
            sb.Append("\t" + grInst + ".map = map" + grInstAbrev + "; " + eol);
            sb.Append("\t" + grInst + ".mapColour = new Color(" + mapColour.r + "f," + mapColour.g + "f," + mapColour.b + "f," + mapColour.a + "f); " + eol);
            sb.Append("\t" + grInst + ".mapTolerance = " + mapTolerance + "; " + eol);
            sb.Append("\t" + grInst + ".mapInverse = " + mapInverse.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + grInst + ".mapToleranceBlendCurve = LBMap.GetDefaultToleranceBlendCurve; " + eol);
            sb.Append("\t" + grInst + ".mapIsPath = " + mapIsPath.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + grInst + ".isDisabled = " + isDisabled.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + grInst + ".showGrass = " + showGrass.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + grInst + ".useNoise = " + useNoise.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + grInst + ".noiseTileSize = " + noiseTileSize + "f; " + eol);
            sb.Append("\t" + grInst + ".grassPlacementCutoff = " + grassPlacementCutoff + "f; " + eol);
            sb.Append("\t" + grInst + ".noiseOctaves = " + noiseOctaves + "; " + eol);
            sb.Append("\t" + grInst + ".useMeshPrefab = " + useMeshPrefab.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + grInst + ".meshPrefab = meshPrefab" + grInstAbrev + "; " + eol);
            sb.Append("\t" + grInst + ".meshPrefabName = " + (string.IsNullOrEmpty(meshPrefabName) ? "\"\"" : "\"" + meshPrefabName + "\"") + "; " + eol);
            sb.Append("\t" + grInst + ".showPrefabPreview = " + showPrefabPreview.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + grInst + ".GUID = " + (string.IsNullOrEmpty(GUID) ? "\"\"" : "\"" + GUID + "\"") + "; " + eol);

            sb.Append("\t" + grInst + ".filterList = new List<LBFilter>(); " + eol);
            if (filterList != null)
            {
                // Create a unique variable
                if (filterList.Exists(f => f.filterType == LBFilter.FilterType.StencilLayer))
                {
                    sb.Append("\tLBFilter lbFilter" + grInstAbrev + " = null; " + eol);
                }

                for (int tf = 0; tf < filterList.Count; tf++)
                {
                    LBFilter lbFilter = filterList[tf];

                    if (lbFilter != null)
                    {
                        if (lbFilter.filterType == LBFilter.FilterType.StencilLayer)
                        {
                            sb.Append("\tlbFilter" + grInstAbrev + " = LBFilter.CreateFilter(\"" + lbFilter.lbStencilGUID + "\", \"" + lbFilter.lbStencilLayerGUID + "\", false); " + eol);
                            sb.Append("\tif (lbFilter" + grInstAbrev + " != null) " + eol);
                            sb.Append("\t{ " + eol);
                            sb.Append("\t\tlbFilter" + grInstAbrev + ".filterMode = LBFilter.FilterMode." + lbFilter.filterMode + ";" + eol);
                            sb.Append("\t\t" + grInst + ".filterList.Add(lbFilter" + grInstAbrev + "); " + eol);
                            sb.Append("\t} " + eol);
                            sb.Append(eol);
                        }
                        else
                        {
                            sb.Append("\t// Currently we do not output non-Stencil filters for runtime Grass. Contact support or post in our Unity forum if you need this feature." + eol);
                        }
                    }
                }
            }

            sb.Append("\t" + grInst + ".lbTerrainDataList = null; " + eol);

            sb.Append("\t// NOTE Add the new Grass to the landscape meta-data");
            sb.Append(eol);
            sb.Append("\tlandscape.terrainGrassList.Add(" + grInst + ");");
            sb.Append(eol);

            sb.Append("}" + eol);
            sb.Append("#endregion" + eol);
            sb.Append("// END OF CODE SEGMENT" + eol);

            return(sb.ToString());
        }
 /// <summary>
 /// Constructor to create a clone of a LBTerrainGrass instance
 /// </summary>
 /// <param name="lbTerrainGrass"></param>
 public LBTerrainGrass(LBTerrainGrass lbTerrainGrass)
 {
     this.texture = lbTerrainGrass.texture;
     if (lbTerrainGrass.textureName == null)
     {
         this.textureName = string.Empty;
     }
     else
     {
         this.textureName = lbTerrainGrass.textureName;
     }
     this.minHeight              = lbTerrainGrass.minHeight;
     this.maxHeight              = lbTerrainGrass.maxHeight;
     this.minWidth               = lbTerrainGrass.minWidth;
     this.maxWidth               = lbTerrainGrass.maxWidth;
     this.healthyColour          = lbTerrainGrass.healthyColour;
     this.dryColour              = lbTerrainGrass.dryColour;
     this.noiseSpread            = lbTerrainGrass.noiseSpread;
     this.minPopulatedHeight     = lbTerrainGrass.minPopulatedHeight;
     this.maxPopulatedHeight     = lbTerrainGrass.maxPopulatedHeight;
     this.minInclination         = lbTerrainGrass.minInclination;
     this.maxInclination         = lbTerrainGrass.maxInclination;
     this.influence              = lbTerrainGrass.influence;
     this.minDensity             = lbTerrainGrass.minDensity;
     this.density                = lbTerrainGrass.density;
     this.detailRenderMode       = lbTerrainGrass.detailRenderMode;
     this.isCurvatureConcave     = lbTerrainGrass.isCurvatureConcave;
     this.curvatureDistance      = lbTerrainGrass.curvatureDistance;
     this.curvatureMinHeightDiff = lbTerrainGrass.curvatureMinHeightDiff;
     this.grassPlacingMode       = lbTerrainGrass.grassPlacingMode;
     this.grassPatchFadingMode   = lbTerrainGrass.grassPatchFadingMode;
     this.map                    = lbTerrainGrass.map;
     this.mapColour              = lbTerrainGrass.mapColour;
     this.mapTolerance           = lbTerrainGrass.mapTolerance;
     this.mapInverse             = lbTerrainGrass.mapInverse;
     this.mapToleranceBlendCurve = lbTerrainGrass.mapToleranceBlendCurve;
     this.mapIsPath              = lbTerrainGrass.mapIsPath;
     this.isDisabled             = lbTerrainGrass.isDisabled;
     if (lbTerrainGrass.filterList != null)
     {
         this.filterList = LBFilter.CopyList(lbTerrainGrass.filterList);
     }
     else
     {
         this.filterList = new List <LBFilter>();
     }
     this.showGrass            = lbTerrainGrass.showGrass;
     this.useNoise             = lbTerrainGrass.useNoise;
     this.noiseTileSize        = lbTerrainGrass.noiseTileSize;
     this.noiseOctaves         = lbTerrainGrass.noiseOctaves;
     this.grassPlacementCutoff = lbTerrainGrass.grassPlacementCutoff;
     if (lbTerrainGrass.lbTerrainDataList == null)
     {
         this.lbTerrainDataList = null;
     }
     else
     {
         this.lbTerrainDataList = new List <LBTerrainData>(lbTerrainGrass.lbTerrainDataList);
     }
     this.useMeshPrefab = lbTerrainGrass.useMeshPrefab;
     this.meshPrefab    = lbTerrainGrass.meshPrefab;
     if (lbTerrainGrass.meshPrefabName == null)
     {
         this.meshPrefabName = string.Empty;
     }
     else
     {
         this.meshPrefabName = lbTerrainGrass.meshPrefabName;
     }
     this.showPrefabPreview = lbTerrainGrass.showPrefabPreview;
     this.GUID = lbTerrainGrass.GUID;
 }
        /// <summary>
        /// Constructor for cloning a layer
        /// </summary>
        /// <param name="lbLandscapeMesh"></param>
        public LBLandscapeMesh(LBLandscapeMesh lbLandscapeMesh)
        {
            this.mesh               = lbLandscapeMesh.mesh;
            this.materials          = new List <Material>(lbLandscapeMesh.materials);
            this.offset             = lbLandscapeMesh.offset;
            this.maxMeshes          = lbLandscapeMesh.maxMeshes;
            this.minProximity       = lbLandscapeMesh.minProximity;
            this.randomiseYRotation = lbLandscapeMesh.randomiseYRotation;
            this.fixedYRotation     = lbLandscapeMesh.fixedYRotation;
            this.XRotation          = lbLandscapeMesh.XRotation;
            this.ZRotation          = lbLandscapeMesh.ZRotation;
            this.isTerrainAligned   = lbLandscapeMesh.isTerrainAligned;
            this.minScale           = lbLandscapeMesh.minScale;
            this.maxScale           = lbLandscapeMesh.maxScale;
            this.minHeight          = lbLandscapeMesh.minHeight;
            this.maxHeight          = lbLandscapeMesh.maxHeight;
            this.minInclination     = lbLandscapeMesh.minInclination;
            this.maxInclination     = lbLandscapeMesh.maxInclination;
            this.meshPlacingMode    = lbLandscapeMesh.meshPlacingMode;

            this.map                    = lbLandscapeMesh.map;
            this.mapColour              = lbLandscapeMesh.mapColour;
            this.mapTolerance           = lbLandscapeMesh.mapTolerance;
            this.mapToleranceBlendCurve = new AnimationCurve(lbLandscapeMesh.mapToleranceBlendCurve.keys);
            this.mapIsPath              = lbLandscapeMesh.mapIsPath;

            this.useNoise            = lbLandscapeMesh.useNoise;
            this.noiseTileSize       = lbLandscapeMesh.noiseTileSize;
            this.noiseOffset         = lbLandscapeMesh.noiseOffset;
            this.meshPlacementCutoff = lbLandscapeMesh.meshPlacementCutoff;

            this.isClustered       = lbLandscapeMesh.isClustered;
            this.clusterDistance   = lbLandscapeMesh.clusterDistance;
            this.clusterDensity    = lbLandscapeMesh.clusterDensity;
            this.clusterResolution = lbLandscapeMesh.clusterResolution;

            this.removeGrass       = lbLandscapeMesh.removeGrass;
            this.minGrassProximity = lbLandscapeMesh.minGrassProximity;

            this.showMesh   = lbLandscapeMesh.showMesh;
            this.isDisabled = lbLandscapeMesh.isDisabled;

            this.usePrefab                = lbLandscapeMesh.usePrefab;
            this.prefab                   = lbLandscapeMesh.prefab;
            this.isCombineMesh            = lbLandscapeMesh.isCombineMesh;
            this.isCreateCollider         = lbLandscapeMesh.isCreateCollider;
            this.isRemoveEmptyGameObjects = lbLandscapeMesh.isRemoveEmptyGameObjects;
            this.minTreeProximity         = lbLandscapeMesh.minTreeProximity;

            this.isTerrainFlattened  = lbLandscapeMesh.isTerrainFlattened;
            this.flattenDistance     = lbLandscapeMesh.flattenDistance;
            this.flattenBlendRate    = lbLandscapeMesh.flattenBlendRate;
            this.flattenHeightOffset = lbLandscapeMesh.flattenHeightOffset;

            if (lbLandscapeMesh.filterList != null)
            {
                this.filterList = LBFilter.CopyList(lbLandscapeMesh.filterList);
            }
            else
            {
                this.filterList = new List <LBFilter>();
            }

            this.isKeepPrefabConnection = lbLandscapeMesh.isKeepPrefabConnection;

            if (lbLandscapeMesh.prefabName == null)
            {
                this.prefabName = string.Empty;
            }
            else
            {
                this.prefabName = lbLandscapeMesh.prefabName;
            }
        }
        /// <summary>
        /// Update the landscape to the current version
        /// v2.0.2 Upgrades the Texture, Grass, and Tree list to include any missing GUIDs.
        /// v2.1.5 Updates Groups to include any missing GUIDs
        /// v2.3.2 Update Texture Filters for Grass and Trees to NOT cutOff value of 0.1
        /// </summary>
        /// <param name="OldVersion"></param>
        /// <param name="NewVersion"></param>
        /// <param name="landscapeToUpdate"></param>
        /// <param name="isSilentUpdate"></param>
        /// <returns></returns>
        public static bool LandscapeUpdate(string OldVersion, string NewVersion, ref LBLandscape landscapeToUpdate, bool isSilentUpdate = false)
        {
            bool isSuccessful = false;

            if (landscapeToUpdate == null)
            {
#if UNITY_EDITOR
                if (!isSilentUpdate)
                {
                    Debug.LogError("LBUpdate LandscapeUpdate - no landscape to update");
                }
#endif
            }
            else
            {
                //Debug.Log("LBUpdate LandscapeUpdate - upgrading " + landscapeToUpdate.gameObject.name + " from version " + OldVersion + " to " + NewVersion);
                landscapeToUpdate.LastUpdatedVersion = NewVersion;

                int majorVersion = landscapeToUpdate.GetLastUpdateMajorVersion;
                int minorVersion = landscapeToUpdate.GetLastUpdateMinorVersion;
                int patchVersion = landscapeToUpdate.GetLastUpdatePatchVersion;

                // Before a Landscape is imported, it doesn't have a grass list, so check first.
                if (landscapeToUpdate.terrainGrassList != null)
                {
                    // Update any Grass types that don't have a GUID
                    List <LBTerrainGrass> updateableGrassList = landscapeToUpdate.terrainGrassList.FindAll(grs => string.IsNullOrEmpty(grs.GUID));

                    int numGrassToUpdate = updateableGrassList == null ? 0 : updateableGrassList.Count;

                    for (int gIdx = 0; gIdx < numGrassToUpdate; gIdx++)
                    {
                        updateableGrassList[gIdx].GUID = System.Guid.NewGuid().ToString();
                    }

                    // Has landscape been created before 2.3.2?
                    // For Texture NOT filters, reset cutOff to default of 0.1 to mimic pre-2.3.2 behaviour.
                    // Fix Texture filter GUIDs
                    if (majorVersion == 1 || (majorVersion == 2 && minorVersion <= 3 && (minorVersion < 3 || patchVersion < 2)))
                    {
                        numGrassToUpdate = landscapeToUpdate.terrainGrassList == null ? 0 : landscapeToUpdate.terrainGrassList.Count;

                        for (int gIdx = 0; gIdx < numGrassToUpdate; gIdx++)
                        {
                            if (LBFilter.Contains(landscapeToUpdate.terrainGrassList[gIdx].filterList, LBFilter.FilterType.Texture))
                            {
                                LBFilter.UpdateTextures(landscapeToUpdate.terrainGrassList[gIdx].filterList, landscapeToUpdate.terrainTexturesList, !isSilentUpdate);

                                foreach (LBFilter lbFilter in landscapeToUpdate.terrainGrassList[gIdx].filterList)
                                {
                                    if (lbFilter != null && lbFilter.filterType == LBFilter.FilterType.Texture && lbFilter.filterMode == LBFilter.FilterMode.NOT && lbFilter.cutOff == 0.5f)
                                    {
                                        lbFilter.cutOff = 0.1f;
                                    }
                                }
                            }
                        }
                    }
                }

                // Before a Landscape is imported, it doesn't have a texture list, so check first.
                if (landscapeToUpdate.terrainTexturesList != null)
                {
                    // Update any Texture types that don't have a GUID
                    List <LBTerrainTexture> updateableTextureList = landscapeToUpdate.terrainTexturesList.FindAll(tx => string.IsNullOrEmpty(tx.GUID));

                    int numTexturesToUpdate = (updateableTextureList == null ? 0 : updateableTextureList.Count);

                    for (int txIdx = 0; txIdx < numTexturesToUpdate; txIdx++)
                    {
                        updateableTextureList[txIdx].GUID = System.Guid.NewGuid().ToString();
                    }
                }

                // Before a Landscape is imported, it doesn't have a tree list, so check first.
                if (landscapeToUpdate.terrainTreesList != null)
                {
                    // Update any Tree types that don't have a GUID
                    List <LBTerrainTree> updateableTreeList = landscapeToUpdate.terrainTreesList.FindAll(tr => string.IsNullOrEmpty(tr.GUID));

                    int numTreesToUpdate = updateableTreeList == null ? 0 : updateableTreeList.Count;

                    for (int trIdx = 0; trIdx < numTreesToUpdate; trIdx++)
                    {
                        updateableTreeList[trIdx].GUID = System.Guid.NewGuid().ToString();
                    }

                    // Has landscape been created before 2.3.2?
                    // For Texture NOT filters, reset cutOff to default of 0.1 to mimic pre-2.3.2 behaviour.
                    if (majorVersion == 1 || (majorVersion == 2 && minorVersion <= 3 && (minorVersion < 3 || patchVersion < 2)))
                    {
                        numTreesToUpdate = landscapeToUpdate.terrainTreesList == null ? 0 : landscapeToUpdate.terrainTreesList.Count;

                        for (int trIdx = 0; trIdx < numTreesToUpdate; trIdx++)
                        {
                            if (LBFilter.Contains(landscapeToUpdate.terrainTreesList[trIdx].filterList, LBFilter.FilterType.Texture))
                            {
                                LBFilter.UpdateTextures(landscapeToUpdate.terrainTreesList[trIdx].filterList, landscapeToUpdate.terrainTexturesList, !isSilentUpdate);

                                foreach (LBFilter lbFilter in landscapeToUpdate.terrainTreesList[trIdx].filterList)
                                {
                                    if (lbFilter != null && lbFilter.filterType == LBFilter.FilterType.Texture && lbFilter.filterMode == LBFilter.FilterMode.NOT && lbFilter.cutOff == 0.5f)
                                    {
                                        lbFilter.cutOff = 0.1f;
                                    }
                                }
                            }
                        }
                    }
                }

                // To use SubGroups, Groups need to have a unique identifier
                if (landscapeToUpdate.lbGroupList != null)
                {
                    // Update any Groups that don't have a GUID
                    List <LBGroup> updateableGroupList = landscapeToUpdate.lbGroupList.FindAll(grp => string.IsNullOrEmpty(grp.GUID));

                    int numGroupsToUpdate = updateableGroupList == null ? 0 : updateableGroupList.Count;

                    for (int gpIdx = 0; gpIdx < numGroupsToUpdate; gpIdx++)
                    {
                        updateableGroupList[gpIdx].GUID = System.Guid.NewGuid().ToString();
                    }
                }

                #if UNITY_EDITOR
                if (!isSilentUpdate)
                {
                    Debug.Log("LBUpdate LandscapeUpdate - upgraded " + landscapeToUpdate.gameObject.name + " from version " + OldVersion + " to " + NewVersion);
                }
                #endif

                isSuccessful = true;
            }

            return(isSuccessful);
        }
        /// <summary>
        /// Script out the Tree for use in a runtime script.
        /// TreeIdx is the zero-based position in the terrainTreesList
        /// </summary>
        /// <param name="TreeIdx"></param>
        /// <param name="EndOfLineMarker"></param>
        /// <returns></returns>
        public string ScriptTree(int TreeIdx, string EndOfLineMarker = "\n")
        {
            // Create a new instance of StringBuilder and give it an estimated capacity
            System.Text.StringBuilder sb = new System.Text.StringBuilder(1000);

            string eol = " ";

            // We always need a space between lines OR a end of line marker like "\n"
            if (EndOfLineMarker.Length > 0)
            {
                eol = EndOfLineMarker;
            }

            string treeInst      = "lbTerrainTree" + (TreeIdx + 1);
            string treeInstAbrev = "Tree" + (TreeIdx + 1);

            sb.Append("// Tree Code generated from Landscape Builder 2 at " + System.DateTime.Now.ToShortTimeString() + " on " + System.DateTime.Now.ToLongDateString() + eol + eol);

            sb.Append("// BEGIN Public variables to populate in the editor - Uncomment and add these to top of class " + eol);
            sb.Append("//[Header(\"Tree" + (TreeIdx + 1) + "\")] " + eol);
            sb.Append("//public GameObject prefab" + treeInstAbrev + "; " + eol);
            sb.Append("//public Texture2D map" + treeInstAbrev + "; " + eol);
            sb.Append("// END Public variables" + eol + eol);

            sb.Append("#region LBTerrainTree" + (TreeIdx + 1) + eol);

            sb.Append("LBTerrainTree " + treeInst + " = new LBTerrainTree(); " + eol);
            sb.Append("if (" + treeInst + " != null)" + eol);
            sb.Append("{" + eol);
            sb.Append("\t" + treeInst + ".maxTreesPerSqrKm = " + maxTreesPerSqrKm + "; " + eol);
            sb.Append("\t" + treeInst + ".bendFactor = " + bendFactor + "f; " + eol);
            sb.Append("\t" + treeInst + ".prefab = prefab" + treeInstAbrev + "; " + eol);
            sb.Append("\t" + treeInst + ".minScale = " + minScale + "f; " + eol);
            sb.Append("\t" + treeInst + ".maxScale = " + maxScale + "f; " + eol);
            sb.Append("\t" + treeInst + ".treeScalingMode = LBTerrainTree.TreeScalingMode." + treeScalingMode + "; " + eol);
            sb.Append("\t" + treeInst + ".lockWidthToHeight = " + lockWidthToHeight.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + treeInst + ".minProximity = " + minProximity + "f; " + eol);
            sb.Append("\t" + treeInst + ".minHeight = " + minHeight + "f; " + eol);
            sb.Append("\t" + treeInst + ".maxHeight = " + maxHeight + "f; " + eol);
            sb.Append("\t" + treeInst + ".minInclination = " + minInclination + "f; " + eol);
            sb.Append("\t" + treeInst + ".maxInclination = " + maxInclination + "f; " + eol);
            sb.Append("\t" + treeInst + ".treePlacingMode = LBTerrainTree.TreePlacingMode." + treePlacingMode + "; " + eol);
            sb.Append("\t" + treeInst + ".isCurvatureConcave = " + isCurvatureConcave.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + treeInst + ".curvatureDistance = " + curvatureDistance + "f; " + eol);
            sb.Append("\t" + treeInst + ".curvatureMinHeightDiff = " + curvatureMinHeightDiff + "f; " + eol);
            sb.Append("\t" + treeInst + ".map = map" + treeInstAbrev + "; " + eol);
            sb.Append("\t" + treeInst + ".mapColour = new Color(" + mapColour.r + "f, " + mapColour.g + "f, " + mapColour.b + "f, " + mapColour.a + "f); " + eol);
            sb.Append("\t" + treeInst + ".mapTolerance = " + mapTolerance + "; " + eol);
            sb.Append("\t" + treeInst + ".mapInverse = " + mapInverse.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + treeInst + ".useNoise = " + useNoise.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + treeInst + ".noiseTileSize = " + noiseTileSize + "f; " + eol);
            sb.Append("\t" + treeInst + ".noiseOffset = " + noiseOffset + "f; " + eol);
            sb.Append("\t" + treeInst + ".treePlacementCutoff = " + treePlacementCutoff + "f; " + eol);
            sb.Append("\t" + treeInst + ".mapToleranceBlendCurve = LBMap.GetDefaultToleranceBlendCurve; " + eol);
            sb.Append("\t" + treeInst + ".mapIsPath = " + mapIsPath.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + treeInst + ".isDisabled = " + isDisabled.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + treeInst + ".offsetY = " + offsetY + "f; " + eol);
            sb.Append("\t" + treeInst + ".showTree = " + showTree.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + treeInst + ".isTinted = " + isTinted.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + treeInst + ".maxTintStrength = " + maxTintStrength + "f; " + eol);
            sb.Append("\t" + treeInst + ".tintColour = new Color(" + tintColour.r + "f, " + tintColour.g + "f, " + tintColour.b + "f, " + tintColour.a + "f); " + eol);
            sb.Append("\t" + treeInst + ".prefabName = " + (string.IsNullOrEmpty(prefabName) ? "\"\"" : "\"" + prefabName + "\"") + "; " + eol);
            sb.Append("\t" + treeInst + ".showPrefabPreview = " + showPrefabPreview.ToString().ToLower() + "; " + eol);
            sb.Append("\t" + treeInst + ".GUID = " + (string.IsNullOrEmpty(GUID) ? "\"\"" : "\"" + GUID + "\"") + "; " + eol);

            sb.Append("\t" + treeInst + ".filterList = new List<LBFilter>(); " + eol);
            if (filterList != null)
            {
                // Create a unique variable
                if (filterList.Exists(f => f.filterType == LBFilter.FilterType.StencilLayer))
                {
                    sb.Append("\tLBFilter lbFilter" + treeInstAbrev + " = null; " + eol);
                }

                for (int tf = 0; tf < filterList.Count; tf++)
                {
                    LBFilter lbFilter = filterList[tf];

                    if (lbFilter != null)
                    {
                        if (lbFilter.filterType == LBFilter.FilterType.StencilLayer)
                        {
                            sb.Append("\tlbFilter" + treeInstAbrev + " = LBFilter.CreateFilter(\"" + lbFilter.lbStencilGUID + "\", \"" + lbFilter.lbStencilLayerGUID + "\", false); " + eol);
                            sb.Append("\tif (lbFilter" + treeInstAbrev + " != null) " + eol);
                            sb.Append("\t{ " + eol);
                            sb.Append("\t\tlbFilter" + treeInstAbrev + ".filterMode = LBFilter.FilterMode." + lbFilter.filterMode + ";" + eol);
                            sb.Append("\t\t" + treeInst + ".filterList.Add(lbFilter" + treeInstAbrev + "); " + eol);
                            sb.Append("\t} " + eol);
                            sb.Append(eol);
                        }
                        else
                        {
                            sb.Append("\t// Currently we do not output non-Stencil filters for runtime Trees. Contact support or post in our Unity forum if you need this feature." + eol);
                        }
                    }
                }
            }

            sb.Append("\t" + treeInst + ".lbTerrainDataList = null; " + eol);

            sb.Append("\t// NOTE Add the new Tree to the landscape meta-data");
            sb.Append(eol);
            sb.Append("\tlandscape.terrainTreesList.Add(" + treeInst + ");");
            sb.Append(eol);

            sb.Append("}" + eol);
            sb.Append("#endregion" + eol);
            sb.Append("// END OF CODE SEGMENT" + eol);

            return(sb.ToString());
        }
        /// <summary>
        /// Clone Constructor
        /// </summary>
        /// <param name="lbTerrainTree"></param>
        public LBTerrainTree(LBTerrainTree lbTerrainTree)
        {
            this.maxTreesPerSqrKm       = lbTerrainTree.maxTreesPerSqrKm;
            this.bendFactor             = lbTerrainTree.bendFactor;
            this.prefab                 = lbTerrainTree.prefab;
            this.minScale               = lbTerrainTree.minScale;
            this.maxScale               = lbTerrainTree.maxScale;
            this.treeScalingMode        = lbTerrainTree.treeScalingMode;
            this.lockWidthToHeight      = lbTerrainTree.lockWidthToHeight;
            this.minProximity           = lbTerrainTree.minProximity;
            this.minHeight              = lbTerrainTree.minHeight;
            this.maxHeight              = lbTerrainTree.maxHeight;
            this.minInclination         = lbTerrainTree.minInclination;
            this.maxInclination         = lbTerrainTree.maxInclination;
            this.treePlacingMode        = lbTerrainTree.treePlacingMode;
            this.isCurvatureConcave     = lbTerrainTree.isCurvatureConcave;
            this.curvatureDistance      = lbTerrainTree.curvatureDistance;
            this.curvatureMinHeightDiff = lbTerrainTree.curvatureMinHeightDiff;
            this.map                    = lbTerrainTree.map;
            this.mapColour              = lbTerrainTree.mapColour;
            this.mapTolerance           = lbTerrainTree.mapTolerance;
            this.mapInverse             = lbTerrainTree.mapInverse;
            this.useNoise               = lbTerrainTree.useNoise;
            this.noiseTileSize          = lbTerrainTree.noiseTileSize;
            this.noiseOffset            = lbTerrainTree.noiseOffset;
            this.treePlacementCutoff    = lbTerrainTree.treePlacementCutoff;
            this.mapToleranceBlendCurve = lbTerrainTree.mapToleranceBlendCurve;
            this.mapIsPath              = lbTerrainTree.mapIsPath;
            this.isDisabled             = lbTerrainTree.isDisabled;
            this.offsetY                = lbTerrainTree.offsetY;
            this.showTree               = lbTerrainTree.showTree;
            if (lbTerrainTree.filterList != null)
            {
                this.filterList = LBFilter.CopyList(lbTerrainTree.filterList);
            }
            else
            {
                this.filterList = new List <LBFilter>();
            }
            this.isTinted        = lbTerrainTree.isTinted;
            this.maxTintStrength = lbTerrainTree.maxTintStrength;
            this.tintColour      = lbTerrainTree.tintColour;
            if (lbTerrainTree.lbTerrainDataList == null)
            {
                this.lbTerrainDataList = null;
            }
            else
            {
                this.lbTerrainDataList = new List <LBTerrainData>(lbTerrainTree.lbTerrainDataList);
            }
            if (lbTerrainTree.prefabName == null)
            {
                this.prefabName = string.Empty;
            }
            else
            {
                this.prefabName = lbTerrainTree.prefabName;
            }
            this.showPrefabPreview = lbTerrainTree.showPrefabPreview;

            this.GUID = lbTerrainTree.GUID;
        }