#if GRIFFIN
#if UNITY_EDITOR
using UnityEngine;
using UnityEngine.Rendering;

namespace Pinwheel.Griffin
{
    public static class GLivePreviewDrawer
    {
        private static MaterialPropertyBlock previewPropertyBlock = new MaterialPropertyBlock();

        public static void DrawGeometryLivePreview(GStylizedTerrain t, Camera cam, Texture newHeightMap, Rect dirtyRect)
        {
            if (t.transform.rotation != Quaternion.identity ||
                t.transform.lossyScale != Vector3.one)
                return;

            Mesh previewMesh = GEditorSettings.Instance.livePreview.GetTriangleMesh(t.TerrainData.Geometry.MeshResolution);

            Vector3 terrainSize = new Vector3(
                t.TerrainData.Geometry.Width,
                t.TerrainData.Geometry.Height,
                t.TerrainData.Geometry.Length);
            previewPropertyBlock.Clear();
            previewPropertyBlock.SetTexture("_OldHeightMap", t.TerrainData.Geometry.HeightMap);
            previewPropertyBlock.SetTexture("_NewHeightMap", newHeightMap);
            previewPropertyBlock.SetTexture("_MainTex", newHeightMap);
            previewPropertyBlock.SetFloat("_Height", t.TerrainData.Geometry.Height);
            previewPropertyBlock.SetVector("_BoundMin", t.transform.position);
            previewPropertyBlock.SetVector("_BoundMax", t.transform.TransformPoint(terrainSize));
            Material mat = GInternalMaterials.GeometryLivePreviewMaterial;
            mat.renderQueue = 4000;

            int gridSize = t.TerrainData.Geometry.ChunkGridSize;
            for (int x = 0; x < gridSize; ++x)
            {
                for (int z = 0; z < gridSize; ++z)
                {
                    Rect uvRect = GCommon.GetUvRange(gridSize, x, z);
                    if (!uvRect.Overlaps(dirtyRect))
                        continue;
                    Vector3 localPos = new Vector3(
                        terrainSize.x * uvRect.x,
                        0f,
                        terrainSize.z * uvRect.y);
                    Vector3 worldPos = t.transform.TransformPoint(localPos);
                    Quaternion rotation = Quaternion.identity;
                    Vector3 scale = new Vector3(terrainSize.x * uvRect.width, 1, terrainSize.z * uvRect.height);

                    Graphics.DrawMesh(
                        previewMesh,
                        Matrix4x4.TRS(worldPos, rotation, scale),
                        mat,
                        LayerMask.NameToLayer("Default"),
                        cam,
                        0,
                        previewPropertyBlock);
                }
            }
        }

        public static void DrawGeometryLivePreview(GStylizedTerrain t, Camera cam, Texture newHeightMap, bool[] chunkCulling)
        {
            if (t.transform.rotation != Quaternion.identity ||
                t.transform.lossyScale != Vector3.one)
                return;

            Mesh previewMesh = GEditorSettings.Instance.livePreview.GetTriangleMesh(t.TerrainData.Geometry.MeshResolution);

            Vector3 terrainSize = new Vector3(
                t.TerrainData.Geometry.Width,
                t.TerrainData.Geometry.Height,
                t.TerrainData.Geometry.Length);
            previewPropertyBlock.Clear();
            previewPropertyBlock.SetTexture("_OldHeightMap", t.TerrainData.Geometry.HeightMap);
            previewPropertyBlock.SetTexture("_NewHeightMap", newHeightMap);
            previewPropertyBlock.SetTexture("_MainTex", newHeightMap);
            previewPropertyBlock.SetFloat("_Height", t.TerrainData.Geometry.Height);
            previewPropertyBlock.SetVector("_BoundMin", t.transform.position);
            previewPropertyBlock.SetVector("_BoundMax", t.transform.TransformPoint(terrainSize));
            Material mat = GInternalMaterials.GeometryLivePreviewMaterial;
            mat.renderQueue = 4000;

            Rect[] chunkRects = t.GetChunkRects();
            for (int i = 0; i < chunkRects.Length; ++i)
            {
                if (chunkCulling[i] == false)
                    continue;
                Rect r = chunkRects[i];
                Vector3 position = new Vector3(r.x, t.transform.position.y, r.y);
                Quaternion rotation = Quaternion.identity;
                Vector3 scale = new Vector3(r.width, 1, r.height);
                Matrix4x4 trs = Matrix4x4.TRS(position, rotation, scale);

                Graphics.DrawMesh(
                    previewMesh,
                    trs,
                    mat,
                    LayerMask.NameToLayer("Default"),
                    cam,
                    0,
                    previewPropertyBlock,
                    ShadowCastingMode.Off,
                    false,
                    null,
                    LightProbeUsage.Off,
                    null);
            }
        }

        public static void DrawSubdivLivePreview(GStylizedTerrain t, Camera cam, Texture newHeightMap, Rect dirtyRect, Texture mask, Matrix4x4 worldPointToMaskMatrix)
        {
            if (t.transform.rotation != Quaternion.identity ||
                t.transform.lossyScale != Vector3.one)
                return;

            t.TerrainData.Geometry.Internal_CreateNewSubDivisionMap(newHeightMap);

            int baseResolution = t.TerrainData.Geometry.MeshBaseResolution;
            int resolution = t.TerrainData.Geometry.MeshResolution;
            int maxLevel = baseResolution + Mathf.Min(Mathf.FloorToInt(1f / GCommon.SUB_DIV_STEP), resolution - baseResolution);

            Vector3 terrainSize = new Vector3(
                t.TerrainData.Geometry.Width,
                t.TerrainData.Geometry.Height,
                t.TerrainData.Geometry.Length);
            previewPropertyBlock.Clear();
            previewPropertyBlock.SetColor("_Color", new Color(0, 0, 0, 0.6f));
            previewPropertyBlock.SetTexture("_HeightMap", newHeightMap);
            previewPropertyBlock.SetVector("_Dimension", terrainSize);
            previewPropertyBlock.SetVector("_BoundMin", t.transform.position);
            previewPropertyBlock.SetVector("_BoundMax", t.transform.TransformPoint(terrainSize));
            previewPropertyBlock.SetTexture("_SubdivMap", t.TerrainData.Geometry.Internal_SubDivisionMap);
            previewPropertyBlock.SetTexture("_Mask", mask);
            previewPropertyBlock.SetMatrix("_WorldPointToMask", worldPointToMaskMatrix);

            Material mat = GInternalMaterials.SubdivLivePreviewMaterial;
            mat.renderQueue = 4000;
            Mesh previewMesh = null;

            int gridSize = t.TerrainData.Geometry.ChunkGridSize;
            for (int x = 0; x < gridSize; ++x)
            {
                for (int z = 0; z < gridSize; ++z)
                {
                    Rect uvRect = GCommon.GetUvRange(gridSize, x, z);
                    if (!uvRect.Overlaps(dirtyRect))
                        continue;
                    Vector3 localPos = new Vector3(
                        terrainSize.x * uvRect.x,
                        0f,
                        terrainSize.z * uvRect.y);
                    Vector3 worldPos = t.transform.TransformPoint(localPos);
                    Quaternion rotation = Quaternion.identity;
                    Vector3 scale = new Vector3(terrainSize.x * uvRect.width, 1, terrainSize.z * uvRect.height);

                    for (int i = baseResolution; i <= maxLevel; ++i)
                    {
                        previewMesh = GEditorSettings.Instance.livePreview.GetWireframeMesh(i);
                        previewPropertyBlock.SetVector("_SubdivRange", new Vector4(
                            (i - baseResolution) * GCommon.SUB_DIV_STEP,
                            i != maxLevel ? (i - baseResolution + 1) * GCommon.SUB_DIV_STEP : 1f,
                            0, 0));

                        Graphics.DrawMesh(
                            previewMesh,
                            Matrix4x4.TRS(worldPos, rotation, scale),
                            mat,
                            LayerMask.NameToLayer("Default"),
                            cam,
                            0,
                            previewPropertyBlock);
                    }
                }
            }
        }

        public static void DrawVisibilityLivePreview(GStylizedTerrain t, Camera cam, Texture newHeightMap, Rect dirtyRect, Texture mask, Matrix4x4 worldPointToMaskMatrix)
        {
            if (t.transform.rotation != Quaternion.identity ||
                t.transform.lossyScale != Vector3.one)
                return;

            t.TerrainData.Geometry.Internal_CreateNewSubDivisionMap(newHeightMap);
            int baseResolution = t.TerrainData.Geometry.MeshBaseResolution;
            int resolution = t.TerrainData.Geometry.MeshResolution;
            int maxLevel = baseResolution + Mathf.Min(Mathf.FloorToInt(1f / GCommon.SUB_DIV_STEP), resolution - baseResolution);

            Vector3 terrainSize = new Vector3(
                t.TerrainData.Geometry.Width,
                t.TerrainData.Geometry.Height,
                t.TerrainData.Geometry.Length);
            previewPropertyBlock.Clear();
            previewPropertyBlock.SetColor("_Color", new Color(0, 0, 0, 0.6f));
            previewPropertyBlock.SetTexture("_HeightMap", newHeightMap);
            previewPropertyBlock.SetVector("_Dimension", terrainSize);
            previewPropertyBlock.SetVector("_BoundMin", t.transform.position);
            previewPropertyBlock.SetVector("_BoundMax", t.transform.TransformPoint(terrainSize));
            previewPropertyBlock.SetTexture("_SubdivMap", t.TerrainData.Geometry.Internal_SubDivisionMap);
            if (mask == null)
                mask = Texture2D.whiteTexture;
            previewPropertyBlock.SetTexture("_Mask", mask);
            previewPropertyBlock.SetMatrix("_WorldPointToMask", worldPointToMaskMatrix);

            Material mat = GInternalMaterials.VisibilityLivePreviewMaterial;
            mat.EnableKeyword("USE_MASK");
            mat.renderQueue = 4000;
            Mesh previewMesh = null;

            int gridSize = t.TerrainData.Geometry.ChunkGridSize;
            for (int x = 0; x < gridSize; ++x)
            {
                for (int z = 0; z < gridSize; ++z)
                {
                    Rect uvRect = GCommon.GetUvRange(gridSize, x, z);
                    if (!uvRect.Overlaps(dirtyRect))
                        continue;
                    Vector3 localPos = new Vector3(
                        terrainSize.x * uvRect.x,
                        0f,
                        terrainSize.z * uvRect.y);
                    Vector3 worldPos = t.transform.TransformPoint(localPos);
                    Quaternion rotation = Quaternion.identity;
                    Vector3 scale = new Vector3(terrainSize.x * uvRect.width, 1, terrainSize.z * uvRect.height);

                    for (int i = baseResolution; i <= maxLevel; ++i)
                    {
                        previewMesh = GEditorSettings.Instance.livePreview.GetWireframeMesh(i);
                        previewPropertyBlock.SetVector("_SubdivRange", new Vector4(
                            (i - baseResolution) * GCommon.SUB_DIV_STEP,
                            i != maxLevel ? (i - baseResolution + 1) * GCommon.SUB_DIV_STEP : 1f,
                            0, 0));

                        Graphics.DrawMesh(
                            previewMesh,
                            Matrix4x4.TRS(worldPos, rotation, scale),
                            mat,
                            LayerMask.NameToLayer("Default"),
                            cam,
                            0,
                            previewPropertyBlock);
                    }
                }
            }
        }

        public static void DrawVisibilityLivePreview(GStylizedTerrain t, Camera cam, Texture newHeightMap, bool[] chunkCulling, Texture mask, Matrix4x4 worldPointToMaskMatrix)
        {
            if (t.transform.rotation != Quaternion.identity ||
                t.transform.lossyScale != Vector3.one)
                return;

            t.TerrainData.Geometry.Internal_CreateNewSubDivisionMap(newHeightMap);
            int baseResolution = t.TerrainData.Geometry.MeshBaseResolution;
            int resolution = t.TerrainData.Geometry.MeshResolution;
            int maxLevel = baseResolution + Mathf.Min(Mathf.FloorToInt(1f / GCommon.SUB_DIV_STEP), resolution - baseResolution);

            Vector3 terrainSize = new Vector3(
                t.TerrainData.Geometry.Width,
                t.TerrainData.Geometry.Height,
                t.TerrainData.Geometry.Length);
            previewPropertyBlock.Clear();
            previewPropertyBlock.SetColor("_Color", new Color(0, 0, 0, 0.6f));
            previewPropertyBlock.SetTexture("_HeightMap", newHeightMap);
            previewPropertyBlock.SetVector("_Dimension", terrainSize);
            previewPropertyBlock.SetVector("_BoundMin", t.transform.position);
            previewPropertyBlock.SetVector("_BoundMax", t.transform.TransformPoint(terrainSize));
            previewPropertyBlock.SetTexture("_SubdivMap", t.TerrainData.Geometry.Internal_SubDivisionMap);
            if (mask == null)
                mask = Texture2D.whiteTexture;
            previewPropertyBlock.SetTexture("_Mask", mask);
            previewPropertyBlock.SetMatrix("_WorldPointToMask", worldPointToMaskMatrix);

            Material mat = GInternalMaterials.VisibilityLivePreviewMaterial;
            mat.EnableKeyword("USE_MASK");
            mat.renderQueue = 4000;
            Mesh previewMesh = null;

            Rect[] chunkRects = t.GetChunkRects();
            for (int i = 0; i < chunkRects.Length; ++i)
            {
                if (chunkCulling[i] == false)
                    continue;
                Rect r = chunkRects[i];
                Vector3 position = new Vector3(r.x, t.transform.position.y, r.y);
                Quaternion rotation = Quaternion.identity;
                Vector3 scale = new Vector3(r.width, 1, r.height);
                Matrix4x4 trs = Matrix4x4.TRS(position, rotation, scale);

                for (int res = baseResolution; res <= maxLevel; ++res)
                {
                    previewMesh = GEditorSettings.Instance.livePreview.GetWireframeMesh(res);
                    previewPropertyBlock.SetVector("_SubdivRange", new Vector4(
                        (res - baseResolution) * GCommon.SUB_DIV_STEP,
                        res != maxLevel ? (res - baseResolution + 1) * GCommon.SUB_DIV_STEP : 1f,
                        0, 0));

                    Graphics.DrawMesh(
                        previewMesh,
                        trs,
                        mat,
                        LayerMask.NameToLayer("Default"),
                        cam,
                        0,
                        previewPropertyBlock,
                        ShadowCastingMode.Off,
                        false,
                        null,
                        LightProbeUsage.Off,
                        null);
                }
            }
        }

        public static void DrawVisibilityLivePreview(GStylizedTerrain t, Camera cam, Texture newHeightMap, Rect dirtyRect)
        {
            if (t.transform.rotation != Quaternion.identity ||
                t.transform.lossyScale != Vector3.one)
                return;

            t.TerrainData.Geometry.Internal_CreateNewSubDivisionMap(newHeightMap);
            int baseResolution = t.TerrainData.Geometry.MeshBaseResolution;
            int resolution = t.TerrainData.Geometry.MeshResolution;
            int maxLevel = baseResolution + Mathf.Min(Mathf.FloorToInt(1f / GCommon.SUB_DIV_STEP), resolution - baseResolution);

            Vector3 terrainSize = new Vector3(
                t.TerrainData.Geometry.Width,
                t.TerrainData.Geometry.Height,
                t.TerrainData.Geometry.Length);
            previewPropertyBlock.Clear();
            previewPropertyBlock.SetColor("_Color", new Color(0, 0, 0, 0.6f));
            previewPropertyBlock.SetTexture("_HeightMap", newHeightMap);
            previewPropertyBlock.SetVector("_Dimension", terrainSize);
            previewPropertyBlock.SetVector("_BoundMin", t.transform.position);
            previewPropertyBlock.SetVector("_BoundMax", t.transform.TransformPoint(terrainSize));
            previewPropertyBlock.SetTexture("_SubdivMap", t.TerrainData.Geometry.Internal_SubDivisionMap);

            Material mat = GInternalMaterials.VisibilityLivePreviewMaterial;
            mat.DisableKeyword("USE_MASK");
            mat.renderQueue = 4000;
            Mesh previewMesh = null;

            int gridSize = t.TerrainData.Geometry.ChunkGridSize;
            for (int x = 0; x < gridSize; ++x)
            {
                for (int z = 0; z < gridSize; ++z)
                {
                    Rect uvRect = GCommon.GetUvRange(gridSize, x, z);
                    if (!uvRect.Overlaps(dirtyRect))
                        continue;
                    Vector3 localPos = new Vector3(
                        terrainSize.x * uvRect.x,
                        0f,
                        terrainSize.z * uvRect.y);
                    Vector3 worldPos = t.transform.TransformPoint(localPos);
                    Quaternion rotation = Quaternion.identity;
                    Vector3 scale = new Vector3(terrainSize.x * uvRect.width, 1, terrainSize.z * uvRect.height);

                    for (int i = baseResolution; i <= maxLevel; ++i)
                    {
                        previewMesh = GEditorSettings.Instance.livePreview.GetWireframeMesh(i);
                        previewPropertyBlock.SetVector("_SubdivRange", new Vector4(
                            (i - baseResolution) * GCommon.SUB_DIV_STEP,
                            i != maxLevel ? (i - baseResolution + 1) * GCommon.SUB_DIV_STEP : 1f,
                            0, 0));

                        Graphics.DrawMesh(
                            previewMesh,
                            Matrix4x4.TRS(worldPos, rotation, scale),
                            mat,
                            LayerMask.NameToLayer("Default"),
                            cam,
                            0,
                            previewPropertyBlock);
                    }
                }
            }
        }

        public static void DrawAlbedoLivePreview(GStylizedTerrain t, Camera cam, Texture newAlbedo, Rect dirtyRect)
        {
            Material mat = t.TerrainData.Shading.MaterialToRender;
            if (mat == null)
                return;

            previewPropertyBlock.Clear();
            if (!string.IsNullOrEmpty(t.TerrainData.Shading.AlbedoMapPropertyName))
            {
                previewPropertyBlock.SetTexture(t.TerrainData.Shading.AlbedoMapPropertyName, newAlbedo);
            }

            GTerrainChunk[] chunks = t.GetChunks();
            for (int i = 0; i < chunks.Length; ++i)
            {
                Rect uvRange = chunks[i].GetUvRange();
                if (uvRange.Overlaps(dirtyRect))
                {
                    Mesh chunkMesh = chunks[i].GetMesh(0);
                    if (chunkMesh != null)
                    {
                        Graphics.DrawMesh(
                            chunkMesh,
                            chunks[i].transform.localToWorldMatrix * Matrix4x4.Translate(Vector3.up * 0.01f),
                            mat,
                            chunks[i].gameObject.layer,
                            cam,
                            0,
                            previewPropertyBlock,
                            t.TerrainData.Rendering.CastShadow,
                            t.TerrainData.Rendering.ReceiveShadow);
                    }
                }
            }
        }

        public static void DrawMetallicSmoothnessLivePreview(GStylizedTerrain t, Camera cam, Texture newMetallicMap, Rect dirtyRect)
        {
            Material mat = t.TerrainData.Shading.MaterialToRender;
            if (mat == null)
                return;

            previewPropertyBlock.Clear();
            if (!string.IsNullOrEmpty(t.TerrainData.Shading.MetallicMapPropertyName))
            {
                previewPropertyBlock.SetTexture(t.TerrainData.Shading.MetallicMapPropertyName, newMetallicMap);
            }

            GTerrainChunk[] chunks = t.GetChunks();
            for (int i = 0; i < chunks.Length; ++i)
            {
                Rect uvRange = chunks[i].GetUvRange();
                if (uvRange.Overlaps(dirtyRect))
                {
                    Mesh chunkMesh = chunks[i].GetMesh(0);
                    if (chunkMesh != null)
                    {
                        Graphics.DrawMesh(
                            chunkMesh,
                            chunks[i].transform.localToWorldMatrix * Matrix4x4.Translate(Vector3.up * 0.01f),
                            mat,
                            chunks[i].gameObject.layer,
                            cam,
                            0,
                            previewPropertyBlock,
                            t.TerrainData.Rendering.CastShadow,
                            t.TerrainData.Rendering.ReceiveShadow);
                    }
                }
            }
        }

        public static void DrawAMSLivePreview(GStylizedTerrain t, Camera cam, Texture newAlbedo, Texture newMetallicMap, Rect dirtyRect)
        {
            Material mat = t.TerrainData.Shading.MaterialToRender;
            if (mat == null)
                return;

            previewPropertyBlock.Clear();
            if (!string.IsNullOrEmpty(t.TerrainData.Shading.AlbedoMapPropertyName))
            {
                previewPropertyBlock.SetTexture(t.TerrainData.Shading.AlbedoMapPropertyName, newAlbedo);
            }
            if (!string.IsNullOrEmpty(t.TerrainData.Shading.MetallicMapPropertyName))
            {
                previewPropertyBlock.SetTexture(t.TerrainData.Shading.MetallicMapPropertyName, newMetallicMap);
            }


            GTerrainChunk[] chunks = t.GetChunks();
            for (int i = 0; i < chunks.Length; ++i)
            {
                Rect uvRange = chunks[i].GetUvRange();
                if (uvRange.Overlaps(dirtyRect))
                {

                    Mesh chunkMesh = chunks[i].GetMesh(0);
                    if (chunkMesh != null)
                    {
                        Graphics.DrawMesh(
                            chunkMesh,
                            chunks[i].transform.localToWorldMatrix * Matrix4x4.Translate(Vector3.up * 0.01f),
                            mat,
                            chunks[i].gameObject.layer,
                            cam,
                            0,
                            previewPropertyBlock,
                            t.TerrainData.Rendering.CastShadow,
                            t.TerrainData.Rendering.ReceiveShadow);
                    }
                }
            }
        }

        public static void DrawAMSLivePreview(GStylizedTerrain t, Camera cam, Texture newAlbedo, Texture newMetallicMap, bool[] chunkCulling)
        {
            Material mat = t.TerrainData.Shading.MaterialToRender;
            if (mat == null)
                return;

            previewPropertyBlock.Clear();
            if (!string.IsNullOrEmpty(t.TerrainData.Shading.AlbedoMapPropertyName))
            {
                previewPropertyBlock.SetTexture(t.TerrainData.Shading.AlbedoMapPropertyName, newAlbedo);
            }
            if (!string.IsNullOrEmpty(t.TerrainData.Shading.MetallicMapPropertyName))
            {
                previewPropertyBlock.SetTexture(t.TerrainData.Shading.MetallicMapPropertyName, newMetallicMap);
            }

            int gridSize = t.TerrainData.Geometry.ChunkGridSize;
            GTerrainChunk[] chunks = t.GetChunks();
            for (int i = 0; i < chunks.Length; ++i)
            {
                int chunkIndex = GUtilities.To1DIndex((int)chunks[i].Index.x, (int)chunks[i].Index.y, gridSize);
                if (chunkCulling[chunkIndex] == false)
                    continue;

                Graphics.DrawMesh(
                    chunks[i].GetMesh(0),
                    chunks[i].transform.localToWorldMatrix * Matrix4x4.Translate(Vector3.up * 0.01f),
                    mat,
                    LayerMask.NameToLayer("Default"),
                    cam,
                    0,
                    previewPropertyBlock,
                    ShadowCastingMode.Off,
                    false,
                    null,
                    LightProbeUsage.Off,
                    null);
            }
        }

        public static void DrawSplatLivePreview(GStylizedTerrain t, Camera cam, Texture[] newControlMaps, Rect dirtyRect)
        {
            Material mat = t.TerrainData.Shading.MaterialToRender;
            if (mat == null)
                return;
            int controlMapResolution = t.TerrainData.Shading.SplatControlResolution;
            int controlMapCount = t.TerrainData.Shading.SplatControlMapCount;
            if (controlMapCount == 0)
                return;

            previewPropertyBlock.Clear();
            for (int i = 0; i < controlMapCount; ++i)
            {
                if (!string.IsNullOrEmpty(t.TerrainData.Shading.SplatControlMapPropertyName))
                {
                    previewPropertyBlock.SetTexture(t.TerrainData.Shading.SplatControlMapPropertyName + i, newControlMaps[i] ?? Texture2D.blackTexture);
                }
            }

            GTerrainChunk[] chunks = t.GetChunks();
            for (int i = 0; i < chunks.Length; ++i)
            {
                Rect uvRange = chunks[i].GetUvRange();
                if (uvRange.Overlaps(dirtyRect))
                {
                    Mesh chunkMesh = chunks[i].GetMesh(0);
                    if (chunkMesh != null)
                    {
                        Graphics.DrawMesh(
                            chunkMesh,
                            chunks[i].transform.localToWorldMatrix * Matrix4x4.Translate(Vector3.up * 0.01f),
                            mat,
                            chunks[i].gameObject.layer,
                            cam,
                            0,
                            previewPropertyBlock,
                            t.TerrainData.Rendering.CastShadow,
                            t.TerrainData.Rendering.ReceiveShadow);
                    }
                }
            }
        }


        public static void DrawSplatLivePreview(GStylizedTerrain t, Camera cam, Texture[] newControlMaps, bool[] chunkCulling)
        {
            Material mat = t.TerrainData.Shading.MaterialToRender;
            if (mat == null)
                return;
            int controlMapCount = t.TerrainData.Shading.SplatControlMapCount;
            if (controlMapCount == 0)
                return;

            previewPropertyBlock.Clear();
            for (int i = 0; i < controlMapCount; ++i)
            {
                if (!string.IsNullOrEmpty(t.TerrainData.Shading.SplatControlMapPropertyName))
                {
                    previewPropertyBlock.SetTexture(t.TerrainData.Shading.SplatControlMapPropertyName + i, newControlMaps[i] ?? Texture2D.blackTexture);
                }
            }

            int gridSize = t.TerrainData.Geometry.ChunkGridSize;
            GTerrainChunk[] chunks = t.GetChunks();
            for (int i = 0; i < chunks.Length; ++i)
            {
                int chunkIndex = GUtilities.To1DIndex((int)chunks[i].Index.x, (int)chunks[i].Index.y, gridSize);
                if (chunkCulling[chunkIndex] == false)
                    continue;

                Graphics.DrawMesh(
                    chunks[i].GetMesh(0),
                    chunks[i].transform.localToWorldMatrix * Matrix4x4.Translate(Vector3.up * 0.01f),
                    mat,
                    LayerMask.NameToLayer("Default"),
                    cam,
                    0,
                    previewPropertyBlock,
                    ShadowCastingMode.Off,
                    false,
                    null,
                    LightProbeUsage.Off,
                    null);
            }
        }

        public static void DrawMasksLivePreview(GStylizedTerrain t, Camera cam, Texture[] masks, Color[] colors, Rect dirtyRect, int channel = 0)
        {
            Material mat = GInternalMaterials.MaskVisualizerMaterial;
            if (mat == null)
                return;

            previewPropertyBlock.Clear();
            previewPropertyBlock.SetVector("_Dimension", new Vector4(t.TerrainData.Geometry.Width, t.TerrainData.Geometry.Height, t.TerrainData.Geometry.Length));

            GTerrainChunk[] chunks = t.GetChunks();
            for (int i = 0; i < chunks.Length; ++i)
            {
                Rect uvRange = chunks[i].GetUvRange();
                if (uvRange.Overlaps(dirtyRect))
                {
                    Mesh chunkMesh = chunks[i].GetMesh(0);
                    if (chunkMesh != null)
                    {
                        for (int j = 0; j < masks.Length; ++j)
                        {
                            previewPropertyBlock.SetColor("_Color", colors[j]);
                            previewPropertyBlock.SetTexture("_MainTex", masks[j]);
                            previewPropertyBlock.SetInt("_Channel", channel);
                            Graphics.DrawMesh(
                                chunkMesh,
                                chunks[i].transform.localToWorldMatrix * Matrix4x4.Translate(Vector3.up * 0.05f * j),
                                mat,
                                chunks[i].gameObject.layer,
                                cam,
                                0,
                                previewPropertyBlock,
                                t.TerrainData.Rendering.CastShadow,
                                t.TerrainData.Rendering.ReceiveShadow);
                        }
                    }
                }
            }
        }


        public static void DrawMasksLivePreview(GStylizedTerrain t, Camera cam, Texture[] masks, Color[] colors, bool[] chunkCulling, int channel = 0)
        {
            Material mat = GInternalMaterials.MaskVisualizerMaterial;
            if (mat == null)
                return;

            previewPropertyBlock.Clear();
            previewPropertyBlock.SetVector("_Dimension", new Vector4(t.TerrainData.Geometry.Width, t.TerrainData.Geometry.Height, t.TerrainData.Geometry.Length));

            int gridSize = t.TerrainData.Geometry.ChunkGridSize;
            GTerrainChunk[] chunks = t.GetChunks();
            for (int i = 0; i < chunks.Length; ++i)
            {
                int chunkIndex = GUtilities.To1DIndex((int)chunks[i].Index.x, (int)chunks[i].Index.y, gridSize);
                if (chunkCulling[chunkIndex] == false)
                    continue;
                Mesh chunkMesh = chunks[i].GetMesh(0);
                for (int j = 0; j < masks.Length; ++j)
                {
                    previewPropertyBlock.SetColor("_Color", colors[j]);
                    previewPropertyBlock.SetTexture("_MainTex", masks[j]);
                    previewPropertyBlock.SetInt("_Channel", channel);
                    Graphics.DrawMesh(
                        chunkMesh,
                        chunks[i].transform.localToWorldMatrix * Matrix4x4.Translate(Vector3.up * 0.05f * j),
                        mat,
                        chunks[i].gameObject.layer,
                        cam,
                        0,
                        previewPropertyBlock,
                        t.TerrainData.Rendering.CastShadow,
                        t.TerrainData.Rendering.ReceiveShadow);

                }
            }
        }

        public static void DrawTerrainMask(GStylizedTerrain t, Camera cam)
        {
            if (t.TerrainData == null)
                return;
            GLivePreviewDrawer.DrawMasksLivePreview(
                t, cam,
                new Texture[] { t.TerrainData.Mask.MaskMapOrDefault },
                new Color[] { Color.red },
                GCommon.UnitRect);
        }

        public static void DrawMask4ChannelsLivePreview(GStylizedTerrain t, Camera cam, Texture masks, Rect dirtyRect)
        {
            Material mat = GInternalMaterials.Mask4ChannelsMaterial;
            if (mat == null)
                return;

            previewPropertyBlock.Clear();
            GTerrainChunk[] chunks = t.GetChunks();
            for (int i = 0; i < chunks.Length; ++i)
            {
                Rect uvRange = chunks[i].GetUvRange();
                if (uvRange.Overlaps(dirtyRect))
                {
                    Mesh chunkMesh = chunks[i].GetMesh(0);
                    if (chunkMesh != null)
                    {
                        previewPropertyBlock.SetTexture("_MainTex", masks);
                        Graphics.DrawMesh(
                            chunkMesh,
                            chunks[i].transform.localToWorldMatrix * Matrix4x4.Translate(Vector3.up * 0.05f),
                            mat,
                            chunks[i].gameObject.layer,
                            cam,
                            0,
                            previewPropertyBlock,
                            t.TerrainData.Rendering.CastShadow,
                            t.TerrainData.Rendering.ReceiveShadow);
                    }
                }
            }
        }
    }
}
#endif
#endif