private void ShowDetailPrototypeMessages(DetailPrototype detailPrototype, Terrain terrain)
 {
     if (!DetailPrototype.IsModeSupportedByRenderPipeline(detailPrototype.renderMode, detailPrototype.useInstancing, out var msg) ||
         !detailPrototype.Validate(out msg))
     {
         EditorGUILayout.HelpBox(msg, MessageType.Error);
     }
     else if ((detailPrototype.renderMode != DetailRenderMode.VertexLit || !detailPrototype.useInstancing) &&
              detailPrototype.usePrototypeMesh && detailPrototype.prototype != null &&
              detailPrototype.prototype.TryGetComponent <MeshFilter>(out var meshFilter) &&
              meshFilter.sharedMesh != null)
     {
         var maxVertCount = meshFilter.sharedMesh.vertexCount * PaintDetailsUtils.GetMaxDetailInstances(terrain.terrainData) * terrain.detailObjectDensity;
         if (maxVertCount >= 65536)
         {
             EditorGUILayout.HelpBox(s_Styles.detailVertexWarning.text, MessageType.Warning);
         }
     }
 }
        public override bool OnPaint(Terrain terrain, IOnPaint editContext)
        {
            if (m_TargetTerrain == null ||
                selectedDetail == kInvalidDetail ||
                selectedDetail >= m_TargetTerrain.terrainData.detailPrototypes.Length)
            {
                return(false);
            }

            Texture2D brush = editContext.brushTexture as Texture2D;

            if (brush == null)
            {
                Debug.LogError("Brush texture is not a Texture2D.");
                return(false);
            }

            if (m_BrushRep == null)
            {
                m_BrushRep = new BrushRep();
            }

            PaintTreesDetailsContext ctx = PaintTreesDetailsContext.Create(terrain, editContext.uv);

            for (int t = 0; t < ctx.terrains.Length; ++t)
            {
                Terrain ctxTerrain = ctx.terrains[t];
                if (ctxTerrain != null)
                {
                    int detailPrototype = PaintDetailsUtils.FindDetailPrototype(ctxTerrain, m_TargetTerrain, selectedDetail);
                    if (detailPrototype == kInvalidDetail)
                    {
                        detailPrototype = PaintDetailsUtils.CopyDetailPrototype(ctxTerrain, m_TargetTerrain, selectedDetail);
                    }

                    TerrainData terrainData = ctxTerrain.terrainData;

                    TerrainPaintUtilityEditor.UpdateTerrainDataUndo(terrainData, "Terrain - Detail Edit");

                    int size = (int)Mathf.Max(1.0f, editContext.brushSize * ((float)terrainData.detailResolution / terrainData.size.x));

                    m_BrushRep.CreateFromBrush(brush, size);

                    Vector2 ctxUV = ctx.uvs[t];

                    int xCenter = Mathf.FloorToInt(ctxUV.x * terrainData.detailWidth);
                    int yCenter = Mathf.FloorToInt(ctxUV.y * terrainData.detailHeight);

                    int intRadius   = Mathf.RoundToInt(size) / 2;
                    int intFraction = Mathf.RoundToInt(size) % 2;

                    int xmin = xCenter - intRadius;
                    int ymin = yCenter - intRadius;

                    int xmax = xCenter + intRadius + intFraction;
                    int ymax = yCenter + intRadius + intFraction;

                    if (xmin >= terrainData.detailWidth || ymin >= terrainData.detailHeight || xmax <= 0 || ymax <= 0)
                    {
                        continue;
                    }

                    xmin = Mathf.Clamp(xmin, 0, terrainData.detailWidth - 1);
                    ymin = Mathf.Clamp(ymin, 0, terrainData.detailHeight - 1);

                    xmax = Mathf.Clamp(xmax, 0, terrainData.detailWidth);
                    ymax = Mathf.Clamp(ymax, 0, terrainData.detailHeight);

                    int width  = xmax - xmin;
                    int height = ymax - ymin;

                    float targetStrength = m_DetailsStrength;
                    if (Event.current.shift || Event.current.control)
                    {
                        targetStrength = -targetStrength;
                    }

                    int[] layers = { detailPrototype };
                    if (targetStrength < 0.0F && !Event.current.control)
                    {
                        layers = terrainData.GetSupportedLayers(xmin, ymin, width, height);
                    }

                    for (int i = 0; i < layers.Length; i++)
                    {
                        int[,] alphamap = terrainData.GetDetailLayer(xmin, ymin, width, height, layers[i]);

                        for (int y = 0; y < height; y++)
                        {
                            for (int x = 0; x < width; x++)
                            {
                                int   xBrushOffset = (xmin + x) - (xCenter - intRadius + intFraction);
                                int   yBrushOffset = (ymin + y) - (yCenter - intRadius + intFraction);
                                float opa          = detailOpacity * m_BrushRep.GetStrengthInt(xBrushOffset, yBrushOffset);

                                float targetValue = Mathf.Lerp(alphamap[y, x], targetStrength * terrainData.maxDetailScatterPerRes, opa);
                                alphamap[y, x] = Mathf.Min(Mathf.RoundToInt(targetValue - .5f + Random.value), terrainData.maxDetailScatterPerRes);
                            }
                        }

                        terrainData.SetDetailLayer(xmin, ymin, layers[i], alphamap);
                    }
                }
            }

            return(false);
        }