/// <summary>
 /// メッシュを生成する何か
 /// </summary>
 /// <param name="gen">作ったフラクタル</param>
 /// <param name="type">生成するメッシュの種類</param>
 /// <param name="magnitude">隆起の倍率</param>
 public MeshGenerator(LyapunovGenerator gen, MeshType type, float magnitude)
 {
     this.gen = gen;
     this.type = type;
     this.mesh = new Mesh();
     this.magnitude = magnitude;
     CreateMesh();
 }
        /// <summary>
        /// 高さマップを生成する
        /// </summary>
        /// <param name="gen">生成したリアプノフ</param>
        /// <param name="curve">色曲線</param>
        /// <returns>高さマップ</returns>
        public static Texture2D CreateHeightMap(LyapunovGenerator gen, AnimationCurve curve)
        {
            Texture2D tex = new Texture2D((int)gen.XLength, (int)gen.YLength);
            float diff = 1f / (gen.MaxValue - gen.MinValue);
            Color[] color = new Color[gen.XLength * gen.YLength];

            for (int i = 0; i < (int)gen.XLength; i++)
            {
                for (int j = 0; j < (int)gen.YLength; j++)
                {
                    float val = curve.Evaluate(gen.Result[i, j] * diff);
                    color[i * gen.XLength + j] = new Color(val, val, val, 1);
                }
            }
            tex.SetPixels(color);
            tex.Apply();
            return tex;
        }
        /// <summary>
        /// リアプノフ指数のテクスチャを自動生成する
        /// </summary>
        /// <param name="gen">生成したフラクタル</param>
        public static Texture2D CreateTexture(LyapunovGenerator gen, Color maxColor, Color minColor, AnimationCurve curve)
        {
            Setup setup = new Setup();

            setup.sizeX = gen.XLength;
            setup.sizeY = gen.YLength;
            setup.result = gen.Result;
            setup.texture = new Texture2D((int)setup.sizeX, (int)setup.sizeY);

            setup.min = gen.MinValue;
            setup.max = gen.MaxValue;
            setup.difference = 1 / (0 - setup.min + setup.max);
            setup.minColor = minColor;
            setup.maxColor = maxColor;

            // 差分色を正規化してるところ
            setup.diffColor = setup.maxColor - setup.minColor;
            setup.curve = curve;

            // ここでテクスチャの色を埋めて行く
            SetTextureColor(ref setup, gen);

            return setup.texture;
        }
        /// <summary>
        /// テクスチャの色を設定する
        /// </summary>
        static void SetTextureColor(ref Setup setup, LyapunovGenerator gen)
        {
            for (uint x = 0; x < setup.sizeX; x++)
            {
                for (uint y = 0; y < setup.sizeY; y++)
                {
                    // 0から1の間で正規化されたリアプノフ指数
                    float normalizedLyapunov = gen.Normalized((int)x, (int)y);

                    Color color = setup.diffColor * setup.curve.Evaluate(normalizedLyapunov) + setup.minColor;
                    color.a = 1;

                    setup.texture.SetPixel((int)x, (int)y, color);
                }
            }
            setup.texture.Apply();
        }
    /// <summary>
    /// �v���n�u��ݒ肷��
    /// </summary>
    /// <param name="path">�p�X</param>
    /// <param name="gen">��������A�v�m�t</param>
    /// <param name="mat">�}�e���A��</param>
    /// <param name="hmap">�����}�b�v</param>
    void SetupPrefab(string path, LyapunovGenerator gen, Material mat, Texture2D tex, Texture2D hmap)
    {
        var prefab = EditorUtility.CreateEmptyPrefab(path + this.text + ".prefab");
        GameObject obj = null;
        TerrainSetup setup = new TerrainSetup(
                    this.text, gen, mat, tex, hmap,
                    this.width, this.height, this.depth, this.magnitude,
                    this.maxColor, this.minColor, this.colorCurve);

        // ���b�V���̐���
        switch (this.terrainType)
        {
            case TerrainType.Plane:	// �‚̐���
                obj = TerrainGenerator.CreatePlane(ref setup, ref path);
                break;

            case TerrainType.Box:	// ���̐���
                mat.mainTexture = null;
                obj = TerrainGenerator.CreateBoxies(ref setup);
                break;

            case TerrainType.TemplateBox:	// �H�v�̂Ȃ����̐���
                obj = TerrainGenerator.CreateTemplateBox(ref setup);
                break;

            case TerrainType.Hexagon:	// �Z�p��
                obj = TerrainGenerator.CreateHexagon(ref setup);
                break;

            case TerrainType.TemplateHexagon:	// �Z�p���e���v��
                obj = TerrainGenerator.CreateTemplateHexagon(ref setup);
                break;

            default:
                break;
        }

        EditorUtility.ReplacePrefab(obj, prefab);	// �v���n�u��쐬
    }
    /// <summary>
    /// �t���N�^���𐶐�����Ƃ���
    /// </summary>
    void Generate()
    {
        long now = DateTime.Now.Ticks;
        {
            // ��ƃt�H���_�̐���
            string path = "Assets/Lyapunov_" + this.text + "/";
            if (!Directory.Exists(path))
                AssetDatabase.CreateFolder("Assets", "Lyapunov_" + this.text);

            // ���A�v�m�t�̐���
            bool concave = this.unevenType == UnevenType.Concave ? true : false;
            LyapunovGenerator gen = new LyapunovGenerator(TextReplacement(), (uint)this.width, (uint)this.depth, (uint)this.repeatTimes, concave);

            // �e�N�X�`���̐���
            Texture2D tex = TextureGenerator.CreateTexture(gen, this.maxColor, this.minColor, this.colorCurve);
            AssetDatabase.CreateAsset(tex, path + this.text + "_tex.asset");
            if (this.enableBitmap)
                CreateBitmap(tex, path + this.text + "_bitmap.bmp");

            // �����}�b�v
            Texture2D heightmap = null;
            if (this.enableHeightMap)
            {
                heightmap = TextureGenerator.CreateHeightMap(gen, colorCurve);
                AssetDatabase.CreateAsset(heightmap, path + this.text + "_height.asset");
            }

            // �}�e���A���̐���
            Material mat = SetupMaterial(path, tex);

            // �e�N�X�`���ȊO�̏ꍇ�̂ݐ�������
            if (this.terrainType != TerrainType.Texture)
            {
                // �Q�[���I�u�W�F�N�g�𐶐�
                SetupPrefab(path, gen, mat, tex, heightmap);
            }
        }
        long end = DateTime.Now.Ticks;
        Debug.Log("milli sec:" + (float)(end - now) / 10000f);
    }
 /// <summary>
 /// TerrainGeneratorの設定用構造体
 /// </summary>
 /// <param name="text">生成文字列</param>
 /// <param name="gen">作ったリアプノフ</param>
 /// <param name="mat">マテリアル</param>
 /// <param name="tex">テクスチャ</param>
 /// <param name="width">横幅</param>
 /// <param name="height">高さ</param>
 /// <param name="depth">縦幅</param>
 /// <param name="magnitude">Y軸位置の倍率</param>
 /// <param name="maxColor">色の最大値</param>
 /// <param name="minColor">色の最小値</param>
 /// <param name="curve">色の曲線</param>
 public TerrainSetup(string text, LyapunovGenerator gen, Material mat, Texture2D tex, Texture2D heightMap, int width, int height, int depth, float magnitude, Color maxColor, Color minColor, AnimationCurve curve)
 {
     this.text = text;
     this.gen = gen;
     this.material = mat;
     this.texture = tex;
     this.heightMap = heightMap;
     this.width = width;
     this.height = height;
     this.depth = depth;
     this.positionMagnitude = magnitude;
     this.maxColor = maxColor;
     this.minColor = minColor;
     this.colorCurve = curve;
 }