// ###################################################################################################################
        // ###################################################################################################################
        // ###################################################################################################################

        public override void GenerateNoise(bool update)
        {
            // #### Adds base noise in whole terrain ####
            //generate(dir, type, update);

            NoiseAlgorithm noiseAlgorithm = new NoiseAlgorithm();

            int totalHeight = (_chunks[0, 0].chunkTerrain.terrainData.heightmapHeight - 1) * chunksY;
            int totalWidth  = (_chunks[0, 0].chunkTerrain.terrainData.heightmapWidth - 1) * chunksX;

            int x = 0, y = 0;
            int ix = 1, iy = 1;

            // Starting for first chunk grid ("00")
            // 01 11
            // 00 10
            Terrain chunk      = _chunks[x, y].chunkTerrain;
            Terrain chunk_init = chunk;

            float[,] heights      = chunk.terrainData.GetHeights(0, 0, chunk.terrainData.heightmapHeight, chunk.terrainData.heightmapWidth);
            float[,] heights_init = heights;

            int initH = (int)chunk.transform.position.z;
            int initW = (int)chunk.transform.position.x;

            int endH = initH + totalHeight;
            int endW = initW + totalWidth;

            int currentHeight = initH + (chunk.terrainData.heightmapHeight - 2);
            int currentWidth  = initW + (chunk.terrainData.heightmapWidth - 1);


            Vector2 center = new Vector2(totalWidth * 0.5f, totalHeight * 0.5f);

            float offset             = (chunksX == chunksY ? 0.85f : 1f);
            float MaxDistance2Center = Vector2.Distance(center, new Vector2(0, 0)) * offset;

            // List for store/apply heights optimally
            List <float[, ]> nextHeights = StoreNextHeights(y);


            NoiseLayer noiseLayer = NoiseManager.noiseLayers[NoiseManager.currLayer];

            // Set seed depending of seedIgnore
            noiseLayer.seed.x = (noiseLayer.seedIgnore ? (Random.value * 10f) : noiseLayer.seed.x);
            noiseLayer.seed.y = (noiseLayer.seedIgnore ? (Random.value * 10f) : noiseLayer.seed.y);


            // GetData en auxiliar variable, for don't erase noiseLayer data
            float[] args = noiseLayer.GetData();

            int acum = update ? 0 : 1;

            UnityEditor.Undo.RegisterCompleteObjectUndo(chunk.terrainData, "Noise");

            // Loop total height
            for (int i = initH; i <= endH; i++)
            {
                //Loop total width
                for (int j = initW; j < endW; j++)
                {
                    if (j == currentWidth - 1)
                    {
                        // Store to heights lists
                        nextHeights[x] = heights;

                        ix = 1;
                        x++;

                        if (x < chunksX)
                        {
                            // Get next x-chunk (the chunk "10") , and update limit of currentWidth (cause it have a new position)
                            // 01 11
                            // 00 10
                            chunk         = _chunks[x, y].chunkTerrain;
                            currentWidth += (chunk.terrainData.heightmapWidth - 1);
                            heights       = nextHeights[x];
                        }
                    }
                    else
                    {
                        float noiseValue = 0.0f;

                        // Do noise depending on type noise. See the function
                        noiseValue = noiseLayer.CalculateNoiseValue(noiseAlgorithm, i, j, chunk, args);

                        float distance2center = Vector2.Distance(center, new Vector2(j, i));

                        //float flattenGrade = (dir == "+" || dir == "-" ? 1f : 1f - (distance2center / MaxDistance2Center));
                        float flattenGrade = 1f - (distance2center / MaxDistance2Center);

                        if (!noiseLayer.islandMode)
                        {
                            flattenGrade = 1f;
                        }

                        float heighresult = noiseValue * flattenGrade;

                        // if we have "update" to TRUE then "acum" equals to ZERO,..
                        // so if (heights * acum = 0), then it doesn't accumulate value over previous heights
                        heights[iy, ix] = (heights[iy, ix] * acum) + heighresult;
                        ix++;
                    }
                }

                x  = 0;
                ix = 1;
                iy++;

                if (i == currentHeight - 1)
                {
                    // In our example. Apply first heights in chunks "00" and "10". (In the next chance in chunks "01" and "11"...)
                    ApplyStoreHeights(nextHeights, y);

                    iy = 1;
                    y++;

                    if (y < chunksY)
                    {
                        // Get next y-chunk (the chunk "01") , and update limit of currentHeight (cause it have a new position)
                        // 01 11
                        // 00 10
                        chunk          = _chunks[x, y].chunkTerrain;
                        currentHeight += (chunk.terrainData.heightmapHeight - 2);
                        chunk_init     = chunk;
                        heights_init   = chunk.terrainData.GetHeights(0, 0, chunk.terrainData.heightmapHeight, chunk.terrainData.heightmapWidth);
                        nextHeights    = StoreNextHeights(y);
                    }
                    else
                    {
                        // end algorithm ...
                        return;
                    }
                }
                else
                {
                    // Back to initial chunk (in our example: back to "01")
                    chunk = chunk_init;
                }

                heights      = heights_init;
                currentWidth = (int)chunk.transform.position.x + (chunk.terrainData.heightmapWidth - 1);
            }
        }
        private void Draw(ref float value)
        {
            if (EditorGUILayout.BeginFadeGroup(value))
            {
                GUI.skin = ResourceLoader.Skin3;
                EditorGUILayout.IntField("id", NoiseManager.currLayer + 1);
                GUI.skin = null;

                GUI.skin = ResourceLoader.Skin2;
                for (int i = 0; i < NoiseManager.noiseLayers.Count; ++i)
                {
                    if (GUILayout.Button("NoiseLayer " + (i + 1) + "   ■   " + NoiseManager.noiseLayers[i].noiseData.presetName))
                    {
                        NoiseManager.currLayer = i;
                    }
                }
                GUI.skin = null;


                GUI.skin = ResourceLoader.Skin3;
                EditorGUILayout.BeginHorizontal();

                GUILayout.FlexibleSpace();

                if (GUILayout.Button("+"))
                {
                    NoiseManager.noiseLayers.Add(new NoiseLayer());
                    NoiseManager.Next();
                }
                if (GUILayout.Button("-"))
                {
                    NoiseManager.noiseLayers.RemoveAt(NoiseManager.currLayer);
                    NoiseManager.Next();
                }
                if (GUILayout.Button("Save"))
                {
                    NoiseManager.Save(Paths.NoiseLayers + "NoiseLayerDataSaved");
                }

                if (GUILayout.Button("Load"))
                {
                    NoiseManager.Load(Paths.NoiseLayers + "NoiseLayerDataSaved");
                }

                EditorGUILayout.EndHorizontal();
                GUI.skin = null;

                ResetSkin();

                if (NoiseManager.noiseLayers.Count != 0)
                {
                    EditorGUILayout.Separator();

                    noiseLayer = NoiseManager.noiseLayers[NoiseManager.currLayer];

                    if (!dynamicUpdate)
                    {
                        EditorGUILayout.BeginHorizontal();
                        if (GUILayout.Button("ApplyLayer"))
                        {
                            addnoise = true;
                        }

                        if (GUILayout.Button("ClearLayer"))
                        {
                            clearnoise = true;
                        }
                        EditorGUILayout.EndHorizontal();

                        EditorGUILayout.BeginHorizontal();
                        if (GUILayout.Button("ApplyAllLayers"))
                        {
                            addnoise  = true;
                            allLayers = true;
                        }

                        if (GUILayout.Button("ClearAllLayers"))
                        {
                            clearnoise = true;
                            allLayers  = true;
                        }
                        EditorGUILayout.EndHorizontal();

                        EditorGUILayout.BeginHorizontal();
                        height = EditorGUILayout.Slider("Modify base height ", height, -1f, 1f);
                        if (GUILayout.Button("Apply"))
                        {
                            WorldManagerInspector.worldManager.ChangeBaseHeight(height);
                            WorldManagerInspector.worldManager.noised = true;
                        }
                        EditorGUILayout.EndHorizontal();
                    }

                    EditorGUILayout.Separator();
                    EditorGUILayout.Separator();


                    noiseLayer.seed       = EditorGUILayout.Vector2Field("Seed", noiseLayer.seed);
                    noiseLayer.seedIgnore = EditorGUILayout.Toggle("RandSeed", noiseLayer.seedIgnore);
                    noiseLayer.islandMode = EditorGUILayout.Toggle("IslandMode", noiseLayer.islandMode);

                    EditorGUILayout.Separator();
                    EditorGUILayout.Separator();

                    show2 = EditorGUILayout.Foldout(show2, "NoiseData");
                    if (show2)
                    {
                        GUI.skin = null;

                        EditorGUILayout.BeginHorizontal();
                        string[] noise_str = new string[3]; int[] noise_int = new int[3];
                        noise_str[0] = eNoise.FRACTAL.ToString(); noise_int[0] = 0;
                        noise_str[1] = eNoise.FBM.ToString(); noise_int[1] = 1;
                        noise_str[2] = eNoise.BILLOW.ToString(); noise_int[2] = 2;

                        noise_selected = EditorGUILayout.IntPopup((int)(noiseLayer.noiseData.type), noise_str, noise_int);
                        dynamicUpdate  = GUILayout.Toggle(dynamicUpdate, "DynamicUpdate");

                        noiseLayer.noiseData.type = (eNoise)(noise_selected);

                        EditorGUILayout.EndHorizontal();

                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.PrefixLabel("Octaves");

                        noiseLayer.noiseData.octaves = EditorGUILayout.IntSlider(noiseLayer.noiseData.octaves, 1, 8);

                        EditorGUILayout.EndHorizontal();
                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.PrefixLabel("Persistence");
                        noiseLayer.noiseData.persistence = EditorGUILayout.Slider(noiseLayer.noiseData.persistence, 0, 2);
                        EditorGUILayout.EndHorizontal();
                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.PrefixLabel("Lacunarity");
                        noiseLayer.noiseData.lacunarity = EditorGUILayout.Slider(noiseLayer.noiseData.lacunarity, 1, 15);
                        EditorGUILayout.EndHorizontal();
                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.PrefixLabel("Frequency");
                        noiseLayer.noiseData.frequency = EditorGUILayout.Slider(noiseLayer.noiseData.frequency, 0, 100);
                        EditorGUILayout.EndHorizontal();
                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.PrefixLabel("Size");
                        noiseLayer.noiseData.size = EditorGUILayout.Slider(noiseLayer.noiseData.size, -50, 50);
                        EditorGUILayout.EndHorizontal();

                        EditorGUILayout.Separator();

                        ResetSkin();

                        show = EditorGUILayout.Foldout(show, "Save/Load Presets");
                        if (show)
                        {
                            PresetHandler();
                        }
                    }

                    if (addnoise || CheckDynamicUpdate())
                    {
                        if (allLayers)
                        {
                            for (int i = 0; i < NoiseManager.noiseLayers.Count; ++i)
                            {
                                manager.GenerateNoise(dynamicUpdate);
                                NoiseManager.Next();
                            }
                            allLayers = false;
                        }
                        else
                        {
                            manager.GenerateNoise(dynamicUpdate);
                        }

                        WorldManagerInspector.worldManager.noised = true;
                        addnoise = false;
                    }

                    if (clearnoise)
                    {
                        if (allLayers)
                        {
                            foreach (NoiseLayer layer in NoiseManager.noiseLayers)
                            {
                                layer.noiseData.size = -1f * layer.noiseData.size;
                                manager.GenerateNoise(dynamicUpdate);
                                layer.noiseData.size = -1f * layer.noiseData.size;
                                NoiseManager.Next();
                            }
                            allLayers = false;
                        }
                        else
                        {
                            noiseLayer.noiseData.size = -1f * noiseLayer.noiseData.size;
                            manager.GenerateNoise(dynamicUpdate);
                            noiseLayer.noiseData.size = -1f * noiseLayer.noiseData.size;
                        }

                        WorldManagerInspector.worldManager.noised = true;
                        clearnoise = false;
                    }

                    SetLastValues();
                }

                GUI.skin = null;

                EditorGUILayout.Separator();
                EditorGUILayout.Separator();

                GUILayout.Box("", new GUILayoutOption[] { GUILayout.ExpandWidth(true), GUILayout.Height(1) });
                EditorGUILayout.Separator();
            }
            EditorGUILayout.EndFadeGroup();
        }