Example #1
0
        public override void OnInspectorGUI()
        {
            //Debug.Log("OnInspectorGUI Called.");
            Event evt = Event.current;

            serializedObject.Update();

            GUILayout.Label("<b>TextMesh Pro! Font Asset</b>", TMP_UIStyleManager.Section_Label);

            // TextMeshPro Font Info Panel
            GUILayout.Label("Face Info", TMP_UIStyleManager.Section_Label);
            EditorGUI.indentLevel = 1;

            GUI.enabled = false; // Lock UI

            float labelWidth = EditorGUIUtility.labelWidth = 135f;
            float fieldWidth = EditorGUIUtility.fieldWidth;

            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Name"), new GUIContent("Font Source"));
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("PointSize"));

            GUI.enabled = true;
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("LineHeight"));

            //GUI.enabled = false;
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Baseline"));

            GUI.enabled = true;
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Ascender"));
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Descender"));
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Underline"));
            //EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("UnderlineThickness"));
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("SuperscriptOffset"));
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("SubscriptOffset"));

            SerializedProperty subSize_prop = m_fontInfo_prop.FindPropertyRelative("SubSize");

            EditorGUILayout.PropertyField(subSize_prop);
            subSize_prop.floatValue = Mathf.Clamp(subSize_prop.floatValue, 0.25f, 1f);


            GUI.enabled = false;
            //EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Padding"));

            //GUILayout.Label("Atlas Size");
            EditorGUI.indentLevel = 1;
            GUILayout.Space(18);
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("AtlasWidth"), new GUIContent("Width"));
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("AtlasHeight"), new GUIContent("Height"));

            GUI.enabled           = true;
            EditorGUI.indentLevel = 0;
            GUILayout.Space(20);
            GUILayout.Label("Font Sub-Assets", TMP_UIStyleManager.Section_Label);

            GUI.enabled           = false;
            EditorGUI.indentLevel = 1;
            EditorGUILayout.PropertyField(font_atlas_prop, new GUIContent("Font Atlas:"));
            EditorGUILayout.PropertyField(font_material_prop, new GUIContent("Font Material:"));

            GUI.enabled = true;

            // Font SETTINGS
            GUILayout.Space(10);
            GUILayout.Label("Face Style", TMP_UIStyleManager.Section_Label);

            string evt_cmd = Event.current.commandName; // Get Current Event CommandName to check for Undo Events

            EditorGUILayout.BeginHorizontal();
            EditorGUIUtility.labelWidth = 110f;
            EditorGUIUtility.fieldWidth = 30f;
            EditorGUILayout.PropertyField(font_normalStyle_prop, new GUIContent("Normal Weight"));
            font_normalStyle_prop.floatValue = Mathf.Clamp(font_normalStyle_prop.floatValue, -3.0f, 3.0f);
            if (GUI.changed || evt_cmd == k_UndoRedo)
            {
                GUI.changed = false;
                Material mat = font_material_prop.objectReferenceValue as Material;
                mat.SetFloat("_WeightNormal", font_normalStyle_prop.floatValue);
            }

            EditorGUIUtility.labelWidth = 90f;
            EditorGUILayout.PropertyField(font_boldStyle_prop, new GUIContent("Bold Weight"));
            font_boldStyle_prop.floatValue = Mathf.Clamp(font_boldStyle_prop.floatValue, -3.0f, 3.0f);
            if (GUI.changed || evt_cmd == k_UndoRedo)
            {
                GUI.changed = false;
                Material mat = font_material_prop.objectReferenceValue as Material;
                mat.SetFloat("_WeightBold", font_boldStyle_prop.floatValue);
            }

            EditorGUIUtility.labelWidth = 100f;
            EditorGUILayout.PropertyField(font_boldSpacing_prop, new GUIContent("Bold Spacing"));
            font_boldSpacing_prop.floatValue = Mathf.Clamp(font_boldSpacing_prop.floatValue, 0, 100);
            if (GUI.changed || evt_cmd == k_UndoRedo)
            {
                GUI.changed = false;
            }
            EditorGUIUtility.labelWidth = labelWidth;
            EditorGUIUtility.fieldWidth = fieldWidth;
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PropertyField(font_italicStyle_prop, new GUIContent("Italic Style: "));
            font_italicStyle_prop.intValue = Mathf.Clamp(font_italicStyle_prop.intValue, 15, 60);

            EditorGUILayout.PropertyField(font_tabSize_prop, new GUIContent("Tab Multiple: "));

            EditorGUILayout.EndHorizontal();


            GUILayout.Space(10);
            EditorGUI.indentLevel = 0;
            if (GUILayout.Button("Glyph Info            \t\t\t" + (UI_PanelState.glyphInfoPanel ? uiStateLabel[1] : uiStateLabel[0]), TMP_UIStyleManager.Section_Label))
            {
                UI_PanelState.glyphInfoPanel = !UI_PanelState.glyphInfoPanel;
            }


            if (UI_PanelState.glyphInfoPanel)
            {
                int arraySize    = m_glyphInfoList_prop.arraySize;
                int itemsPerPage = 15;


                if (arraySize > 0)
                {
                    // Display each GlyphInfo entry using the GlyphInfo property drawer.
                    for (int i = itemsPerPage * m_GlyphPage; i < arraySize && i < itemsPerPage * (m_GlyphPage + 1); i++)
                    {
                        SerializedProperty glyphInfo = m_glyphInfoList_prop.GetArrayElementAtIndex(i);

                        EditorGUILayout.BeginVertical(TMP_UIStyleManager.Group_Label);

                        EditorGUILayout.PropertyField(glyphInfo);

                        EditorGUILayout.EndVertical();
                    }
                }

                Rect pagePos = EditorGUILayout.GetControlRect(false, 20);
                pagePos.width /= 2;

                int shiftMultiplier = evt.shift ? 10 : 1;

                if (m_GlyphPage > 0)
                {
                    GUI.enabled = true;
                }
                else
                {
                    GUI.enabled = false;
                }

                if (GUI.Button(pagePos, "Previous Page"))
                {
                    m_GlyphPage -= 1 * shiftMultiplier;
                }

                pagePos.x += pagePos.width;
                if (itemsPerPage * (m_GlyphPage + 1) < arraySize)
                {
                    GUI.enabled = true;
                }
                else
                {
                    GUI.enabled = false;
                }

                if (GUI.Button(pagePos, "Next Page"))
                {
                    m_GlyphPage += 1 * shiftMultiplier;
                }

                m_GlyphPage = Mathf.Clamp(m_GlyphPage, 0, arraySize / itemsPerPage);
            }


            // KERNING TABLE PANEL

            if (GUILayout.Button("Kerning Table Info\t\t\t" + (UI_PanelState.kerningInfoPanel ? uiStateLabel[1] : uiStateLabel[0]), TMP_UIStyleManager.Section_Label))
            {
                UI_PanelState.kerningInfoPanel = !UI_PanelState.kerningInfoPanel;
            }


            if (UI_PanelState.kerningInfoPanel)
            {
                Rect pos;

                SerializedProperty kerningPairs_prop = m_kerningInfo_prop.FindPropertyRelative("kerningPairs");
                // int pairCount = kerningPairs_prop.arraySize;

                EditorGUILayout.BeginHorizontal();
                GUILayout.Label("Left Char", TMP_UIStyleManager.TMP_GUISkin.label);
                GUILayout.Label("Right Char", TMP_UIStyleManager.TMP_GUISkin.label);
                GUILayout.Label("Offset Value", TMP_UIStyleManager.TMP_GUISkin.label);
                GUILayout.Label(GUIContent.none, GUILayout.Width(20));
                EditorGUILayout.EndHorizontal();

                GUILayout.BeginVertical(TMP_UIStyleManager.TMP_GUISkin.label);

                int arraySize    = kerningPairs_prop.arraySize;
                int itemsPerPage = 25;

                if (arraySize > 0)
                {
                    // Display each GlyphInfo entry using the GlyphInfo property drawer.
                    for (int i = itemsPerPage * m_KerningPage; i < arraySize && i < itemsPerPage * (m_KerningPage + 1); i++)
                    {
                        SerializedProperty kerningPair_prop = kerningPairs_prop.GetArrayElementAtIndex(i);

                        pos = EditorGUILayout.BeginHorizontal();

                        EditorGUI.PropertyField(new Rect(pos.x, pos.y, pos.width - 20f, pos.height), kerningPair_prop, GUIContent.none);

                        // Button to Delete Kerning Pair
                        if (GUILayout.Button("-", GUILayout.ExpandWidth(false)))
                        {
                            m_kerningTable.RemoveKerningPair(i);
                            m_fontAsset.ReadFontDefinition(); // Reload Font Definition.
                            serializedObject.Update();        // Get an updated version of the SerializedObject.
                            isAssetDirty = true;
                            break;
                        }

                        EditorGUILayout.EndHorizontal();
                    }
                }

                Rect pagePos = EditorGUILayout.GetControlRect(false, 20);
                pagePos.width /= 3;

                int shiftMultiplier = evt.shift ? 10 : 1;

                // Previous Page
                if (m_KerningPage > 0)
                {
                    GUI.enabled = true;
                }
                else
                {
                    GUI.enabled = false;
                }

                if (GUI.Button(pagePos, "Previous Page"))
                {
                    m_KerningPage -= 1 * shiftMultiplier;
                }

                // Page Counter
                GUI.enabled = true;
                pagePos.x  += pagePos.width;
                int totalPages = (int)(arraySize / (float)itemsPerPage + 0.999f);
                GUI.Label(pagePos, "Page " + (m_KerningPage + 1) + " / " + totalPages, GUI.skin.button);

                // Next Page
                pagePos.x += pagePos.width;
                if (itemsPerPage * (m_GlyphPage + 1) < arraySize)
                {
                    GUI.enabled = true;
                }
                else
                {
                    GUI.enabled = false;
                }

                if (GUI.Button(pagePos, "Next Page"))
                {
                    m_KerningPage += 1 * shiftMultiplier;
                }

                m_KerningPage = Mathf.Clamp(m_KerningPage, 0, arraySize / itemsPerPage);

                GUILayout.EndVertical();

                GUILayout.Space(10);


                // Add New Kerning Pair Section
                GUILayout.BeginVertical(TMP_UIStyleManager.SquareAreaBox85G);

                pos = EditorGUILayout.BeginHorizontal();

                // Draw Empty Kerning Pair
                EditorGUI.PropertyField(new Rect(pos.x, pos.y, pos.width - 20f, pos.height), m_kerningPair_prop);
                GUILayout.Label(GUIContent.none, GUILayout.Height(19));

                EditorGUILayout.EndHorizontal();

                GUILayout.Space(5);

                if (GUILayout.Button("Add New Kerning Pair"))
                {
                    int   asci_left  = m_kerningPair_prop.FindPropertyRelative("AscII_Left").intValue;
                    int   asci_right = m_kerningPair_prop.FindPropertyRelative("AscII_Right").intValue;
                    float xOffset    = m_kerningPair_prop.FindPropertyRelative("XadvanceOffset").floatValue;

                    errorCode = m_kerningTable.AddKerningPair(asci_left, asci_right, xOffset);

                    // Sort Kerning Pairs & Reload Font Asset if new kerning pair was added.
                    if (errorCode != -1)
                    {
                        m_kerningTable.SortKerningPairs();
                        m_fontAsset.ReadFontDefinition(); // Reload Font Definition.
                        serializedObject.Update();        // Get an updated version of the SerializedObject.
                        isAssetDirty = true;
                    }
                    else
                    {
                        timeStamp = System.DateTime.Now.AddSeconds(5);
                    }
                }

                if (errorCode == -1)
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.FlexibleSpace();
                    GUILayout.Label("Kerning Pair already <color=#ffff00>exists!</color>", TMP_UIStyleManager.Label);
                    GUILayout.FlexibleSpace();
                    GUILayout.EndHorizontal();

                    if (System.DateTime.Now > timeStamp)
                    {
                        errorCode = 0;
                    }
                }

                GUILayout.EndVertical();
            }


            if (serializedObject.ApplyModifiedProperties() || evt_cmd == k_UndoRedo || isAssetDirty)
            {
                //Debug.Log("Serialized properties have changed.");
                TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, m_fontAsset);

                isAssetDirty = false;
                EditorUtility.SetDirty(target);
                //TMPro_EditorUtility.RepaintAll(); // Consider SetDirty
            }
        }
        void Save_SDF_FontAsset(string filePath)
        {
            filePath = filePath.Substring(0, filePath.Length - 6); // Trim file extension from filePath.

            string dataPath = Application.dataPath;

            if (filePath.IndexOf(dataPath) == -1)
            {
                Debug.LogError("You're saving the font asset in a directory outside of this project folder. This is not supported. Please select a directory under \"" + dataPath + "\"");
                return;
            }

            string relativeAssetPath = filePath.Substring(dataPath.Length - 6);
            string tex_DirName       = Path.GetDirectoryName(relativeAssetPath);
            string tex_FileName      = Path.GetFileNameWithoutExtension(relativeAssetPath);
            string tex_Path_NoExt    = tex_DirName + "/" + tex_FileName;


            // Check if TextMeshPro font asset already exists. If not, create a new one. Otherwise update the existing one.
            TextMeshProFont font_asset = AssetDatabase.LoadAssetAtPath(tex_Path_NoExt + ".asset", typeof(TextMeshProFont)) as TextMeshProFont;

            if (font_asset == null)
            {
                //Debug.Log("Creating TextMeshPro font asset!");
                font_asset = ScriptableObject.CreateInstance <TextMeshProFont>(); // Create new TextMeshPro Font Asset.
                AssetDatabase.CreateAsset(font_asset, tex_Path_NoExt + ".asset");

                if (m_destination_Atlas != null)
                {
                    m_font_Atlas = m_destination_Atlas;
                }

                // If using the C# SDF creation mode, we need the scaledown factor.
                int scaleDownFactor = font_renderMode >= RenderModes.DistanceField16 ? 1 : font_scaledownFactor;

                // Add FaceInfo to Font Asset
                FaceInfo face = GetFaceInfo(m_font_faceInfo, scaleDownFactor);
                font_asset.AddFaceInfo(face);

                // Add GlyphInfo[] to Font Asset
                GlyphInfo[] glyphs = GetGlyphInfo(m_font_glyphInfo, scaleDownFactor);
                font_asset.AddGlyphInfo(glyphs);

                // Get and Add Kerning Pairs to Font Asset
                if (includeKerningPairs)
                {
                    string       fontFilePath = AssetDatabase.GetAssetPath(font_TTF);
                    KerningTable kerningTable = GetKerningTable(fontFilePath, (int)face.PointSize);
                    font_asset.AddKerningInfo(kerningTable);
                }

                // Add Line Breaking Rules
                //LineBreakingTable lineBreakingTable = new LineBreakingTable();
                //

                // Add Font Atlas as Sub-Asset
                font_asset.atlas       = m_font_Atlas;
                m_font_Atlas.name      = tex_FileName + " Atlas";
                m_font_Atlas.hideFlags = HideFlags.HideInHierarchy;
                AssetDatabase.AddObjectToAsset(m_font_Atlas, font_asset);

                // Create new Material and Add it as Sub-Asset
                Shader   default_Shader = Shader.Find("TMPro/Distance Field");
                Material tmp_material   = new Material(default_Shader);
                //tmp_material.shaderKeywords = new string[] { "BEVEL_OFF", "GLOW_OFF", "UNDERLAY_OFF" };
                tmp_material.name = tex_FileName + " Material";
                tmp_material.SetTexture(ShaderUtilities.ID_MainTex, m_font_Atlas);
                tmp_material.SetFloat(ShaderUtilities.ID_TextureWidth, m_font_Atlas.width);
                tmp_material.SetFloat(ShaderUtilities.ID_TextureHeight, m_font_Atlas.height);


                tmp_material.SetFloat(ShaderUtilities.ID_WeightNormal, font_asset.NormalStyle);
                tmp_material.SetFloat(ShaderUtilities.ID_WeightBold, font_asset.BoldStyle);

                int spread = font_renderMode >= RenderModes.DistanceField16 ? font_padding + 1 : font_spread;
                tmp_material.SetFloat(ShaderUtilities.ID_GradientScale, spread); // Spread = Padding for Brute Force SDF.

                font_asset.material    = tmp_material;
                tmp_material.hideFlags = HideFlags.HideInHierarchy;
                AssetDatabase.AddObjectToAsset(tmp_material, font_asset);
            }
            else
            {
                // Find all Materials referencing this font atlas.
                Material[] material_references = TMPro_EditorUtility.FindMaterialReferences(font_asset.material);

                // Destroy Assets that will be replaced.
                DestroyImmediate(font_asset.atlas, true);

                int scaleDownFactor = font_renderMode >= RenderModes.DistanceField16 ? 1 : font_scaledownFactor;
                // Add FaceInfo to Font Asset
                FaceInfo face = GetFaceInfo(m_font_faceInfo, scaleDownFactor);
                font_asset.AddFaceInfo(face);

                // Add GlyphInfo[] to Font Asset
                GlyphInfo[] glyphs = GetGlyphInfo(m_font_glyphInfo, scaleDownFactor);
                font_asset.AddGlyphInfo(glyphs);

                // Get and Add Kerning Pairs to Font Asset
                if (includeKerningPairs)
                {
                    string       fontFilePath = AssetDatabase.GetAssetPath(font_TTF);
                    KerningTable kerningTable = GetKerningTable(fontFilePath, (int)face.PointSize);
                    font_asset.AddKerningInfo(kerningTable);
                }

                // Add Font Atlas as Sub-Asset
                font_asset.atlas       = m_font_Atlas;
                m_font_Atlas.name      = tex_FileName + " Atlas";
                m_font_Atlas.hideFlags = HideFlags.HideInHierarchy;
                AssetDatabase.AddObjectToAsset(m_font_Atlas, font_asset);

                // Update the Texture reference on the Material
                for (int i = 0; i < material_references.Length; i++)
                {
                    material_references[i].SetTexture(ShaderUtilities.ID_MainTex, font_asset.atlas);
                    material_references[i].SetFloat(ShaderUtilities.ID_TextureWidth, m_font_Atlas.width);
                    material_references[i].SetFloat(ShaderUtilities.ID_TextureHeight, m_font_Atlas.height);

                    material_references[i].SetFloat(ShaderUtilities.ID_WeightNormal, font_asset.NormalStyle);
                    material_references[i].SetFloat(ShaderUtilities.ID_WeightBold, font_asset.BoldStyle);

                    int spread = font_renderMode >= RenderModes.DistanceField16 ? font_padding + 1 : font_spread;
                    material_references[i].SetFloat(ShaderUtilities.ID_GradientScale, spread); // Spread = Padding for Brute Force SDF.
                }
            }

            // Saving File for Debug
            //var pngData = destination_Atlas.EncodeToPNG();
            //File.WriteAllBytes("Assets/Textures/Debug Distance Field.png", pngData);
            //font_asset.fontCreationSettings = SaveFontCreationSettings();


            AssetDatabase.SaveAssets();

            AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(font_asset));  // Re-import font asset to get the new updated version.

            font_asset.ReadFontDefinition();

            AssetDatabase.Refresh();

            // NEED TO GENERATE AN EVENT TO FORCE A REDRAW OF ANY TEXTMESHPRO INSTANCES THAT MIGHT BE USING THIS FONT ASSET
            TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, font_asset);
        }
Example #3
0
        public override void OnInspectorGUI()
        {
            //Debug.Log("OnInspectorGUI Called.");

            serializedObject.Update();

            GUILayout.Label("<b>TextMesh Pro! Font Asset</b>", SectionLabel);

            // TextMeshPro Font Info Panel
            GUILayout.Label("Face Info", SectionLabel);
            EditorGUI.indentLevel = 1;

            GUI.enabled = false; // Lock UI

            EditorGUIUtility.labelWidth = 135;
            //EditorGUIUtility.fieldWidth = 80;

            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Name"), new GUIContent("Font Source"));
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("PointSize"));

            GUI.enabled = true;
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("LineHeight"));

            GUI.enabled = false;
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Baseline"));
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Ascender"));
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Descender"));
            GUI.enabled = true;
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Underline"));
            //EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("UnderlineThickness"));
            GUI.enabled = false;
            //EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Padding"));

            //GUILayout.Label("Atlas Size");
            EditorGUI.indentLevel = 1;
            GUILayout.Space(18);
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("AtlasWidth"), new GUIContent("Width"));
            EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("AtlasHeight"), new GUIContent("Height"));

            GUI.enabled           = true;
            EditorGUI.indentLevel = 0;
            GUILayout.Space(20);
            GUILayout.Label("Font Sub-Assets", SectionLabel);

            GUI.enabled           = false;
            EditorGUI.indentLevel = 1;
            EditorGUILayout.PropertyField(font_atlas_prop, new GUIContent("Font Atlas:"));
            EditorGUILayout.PropertyField(font_material_prop, new GUIContent("Font Material:"));

            GUI.enabled = true;

            // Font SETTINGS
            GUILayout.Space(10);
            GUILayout.Label("Face Style", SectionLabel);

            string evt_cmd = Event.current.commandName; // Get Current Event CommandName to check for Undo Events

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PropertyField(font_normalStyle_prop, new GUIContent("Normal weight"));
            font_normalStyle_prop.floatValue = Mathf.Clamp(font_normalStyle_prop.floatValue, -3.0f, 3.0f);
            if (GUI.changed || evt_cmd == k_UndoRedo)
            {
                GUI.changed = false;
                Material mat = font_material_prop.objectReferenceValue as Material;
                mat.SetFloat("_WeightNormal", font_normalStyle_prop.floatValue);
            }

            //Rect rect = EditorGUILayout.GetControlRect();
            EditorGUILayout.PropertyField(font_boldStyle_prop, new GUIContent("Bold weight"));
            font_boldStyle_prop.floatValue = Mathf.Clamp(font_boldStyle_prop.floatValue, -3.0f, 3.0f);
            if (GUI.changed || evt_cmd == k_UndoRedo)
            {
                GUI.changed = false;
                Material mat = font_material_prop.objectReferenceValue as Material;
                mat.SetFloat("_WeightBold", font_boldStyle_prop.floatValue);
            }

            EditorGUILayout.EndHorizontal();

            EditorGUILayout.PropertyField(font_italicStyle_prop, new GUIContent("Italic Style: "));
            font_italicStyle_prop.intValue = Mathf.Clamp(font_italicStyle_prop.intValue, 15, 60);

            GUILayout.Space(10);
            EditorGUI.indentLevel = 0;
            if (GUILayout.Button("Glyph Info            \t\t\t" + (UI_PanelState.glyphInfoPanel ? uiStateLabel[1] : uiStateLabel[0]), SectionLabel))
            {
                UI_PanelState.glyphInfoPanel = !UI_PanelState.glyphInfoPanel;
            }


            if (UI_PanelState.glyphInfoPanel)
            {
                if (m_glyphInfoList_prop.arraySize > 0)
                {
                    // Display each GlyphInfo entry using the GlyphInfo property drawer.
                    for (int i = 0; i < m_glyphInfoList_prop.arraySize; i++)
                    {
                        SerializedProperty glyphInfo = m_glyphInfoList_prop.GetArrayElementAtIndex(i);

                        EditorGUILayout.BeginVertical(GroupLabel);

                        EditorGUILayout.PropertyField(glyphInfo);

                        EditorGUILayout.EndVertical();
                    }
                }
            }


            // KERNING TABLE PANEL

            if (GUILayout.Button("Kerning Table Info\t\t\t" + (UI_PanelState.kerningInfoPanel ? uiStateLabel[1] : uiStateLabel[0]), SectionLabel))
            {
                UI_PanelState.kerningInfoPanel = !UI_PanelState.kerningInfoPanel;
            }


            if (UI_PanelState.kerningInfoPanel)
            {
                Rect pos;

                SerializedProperty kerningPairs_prop = m_kerningInfo_prop.FindPropertyRelative("kerningPairs");
                int pairCount = kerningPairs_prop.arraySize;

                EditorGUILayout.BeginHorizontal();
                GUILayout.Label("Left Char", mySkin.label);
                GUILayout.Label("Right Char", mySkin.label);
                GUILayout.Label("Offset Value", mySkin.label);
                GUILayout.Label(GUIContent.none, GUILayout.Width(20));
                EditorGUILayout.EndHorizontal();

                GUILayout.BeginVertical(mySkin.label);

                for (int i = 0; i < pairCount; i++)
                {
                    SerializedProperty kerningPair_prop = kerningPairs_prop.GetArrayElementAtIndex(i);

                    pos = EditorGUILayout.BeginHorizontal();

                    EditorGUI.PropertyField(new Rect(pos.x, pos.y, pos.width - 20f, pos.height), kerningPair_prop, GUIContent.none);

                    // Button to Delete Kerning Pair
                    if (GUILayout.Button("-", GUILayout.ExpandWidth(false)))
                    {
                        m_kerningTable.RemoveKerningPair(i);
                        m_fontAsset.ReadFontDefinition(); // Reload Font Definition.
                        serializedObject.Update();        // Get an updated version of the SerializedObject.
                        isAssetDirty = true;
                        break;
                    }

                    EditorGUILayout.EndHorizontal();
                }

                GUILayout.EndVertical();

                GUILayout.Space(10);


                // Add New Kerning Pair Section
                GUILayout.BeginVertical(SquareAreaBox85G);

                pos = EditorGUILayout.BeginHorizontal();

                // Draw Empty Kerning Pair
                EditorGUI.PropertyField(new Rect(pos.x, pos.y, pos.width - 20f, pos.height), m_kerningPair_prop);
                GUILayout.Label(GUIContent.none, GUILayout.Height(19));

                EditorGUILayout.EndHorizontal();

                GUILayout.Space(5);

                if (GUILayout.Button("Add New Kerning Pair"))
                {
                    int   asci_left  = m_kerningPair_prop.FindPropertyRelative("AscII_Left").intValue;
                    int   asci_right = m_kerningPair_prop.FindPropertyRelative("AscII_Right").intValue;
                    float xOffset    = m_kerningPair_prop.FindPropertyRelative("XadvanceOffset").floatValue;

                    errorCode = m_kerningTable.AddKerningPair(asci_left, asci_right, xOffset);

                    // Sort Kerning Pairs & Reload Font Asset if new kerpair was added.
                    if (errorCode != -1)
                    {
                        m_kerningTable.SortKerningPairs();
                        m_fontAsset.ReadFontDefinition(); // Reload Font Definition.
                        serializedObject.Update();        // Get an updated version of the SerializedObject.
                        isAssetDirty = true;
                    }
                    else
                    {
                        timeStamp = System.DateTime.Now.AddSeconds(5);
                    }
                }

                if (errorCode == -1)
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.FlexibleSpace();
                    GUILayout.Label("Kerning Pair already <color=#ffff00>exists!</color>", mySkin.label);
                    GUILayout.FlexibleSpace();
                    GUILayout.EndHorizontal();

                    if (System.DateTime.Now > timeStamp)
                    {
                        errorCode = 0;
                    }
                }

                GUILayout.EndVertical();
            }


            if (serializedObject.ApplyModifiedProperties() || evt_cmd == k_UndoRedo || isAssetDirty)
            {
                //Debug.Log("Serialized properties have changed.");
                TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, m_fontAsset);

                isAssetDirty = false;
                TMPro_EditorUtility.RepaintAll(); // Consider SetDirty
            }
        }
        void Save_Normal_FontAsset(string filePath)
        {
            filePath = filePath.Substring(0, filePath.Length - 6); // Trim file extension from filePath.

            string dataPath = Application.dataPath;

            if (filePath.IndexOf(dataPath) == -1)
            {
                Debug.LogError("You're saving the font asset in a directory outside of this project folder. This is not supported. Please select a directory under \"" + dataPath + "\"");
                return;
            }

            string relativeAssetPath = filePath.Substring(dataPath.Length - 6);
            string tex_DirName       = Path.GetDirectoryName(relativeAssetPath);
            string tex_FileName      = Path.GetFileNameWithoutExtension(relativeAssetPath);
            string tex_Path_NoExt    = tex_DirName + "/" + tex_FileName;

            // Check if TextMeshPro font asset already exists. If not, create a new one. Otherwise update the existing one.
            TextMeshProFont font_asset = AssetDatabase.LoadAssetAtPath(tex_Path_NoExt + ".asset", typeof(TextMeshProFont)) as TextMeshProFont;

            if (font_asset == null)
            {
                //Debug.Log("Creating TextMeshPro font asset!");
                font_asset = ScriptableObject.CreateInstance <TextMeshProFont>(); // Create new TextMeshPro Font Asset.
                AssetDatabase.CreateAsset(font_asset, tex_Path_NoExt + ".asset");

                // Add FaceInfo to Font Asset
                FaceInfo face = GetFaceInfo(m_font_faceInfo, 1);
                font_asset.AddFaceInfo(face);

                // Add GlyphInfo[] to Font Asset
                GlyphInfo[] glyphs = GetGlyphInfo(m_font_glyphInfo, 1);
                font_asset.AddGlyphInfo(glyphs);

                // Get and Add Kerning Pairs to Font Asset
                if (includeKerningPairs)
                {
                    string       fontFilePath = AssetDatabase.GetAssetPath(font_TTF);
                    KerningTable kerningTable = GetKerningTable(fontFilePath, (int)face.PointSize);
                    font_asset.AddKerningInfo(kerningTable);
                }


                // Add Font Atlas as Sub-Asset
                font_asset.atlas       = m_font_Atlas;
                m_font_Atlas.name      = tex_FileName + " Atlas";
                m_font_Atlas.hideFlags = HideFlags.HideInHierarchy;
                AssetDatabase.AddObjectToAsset(m_font_Atlas, font_asset);

                // Create new Material and Add it as Sub-Asset
                Shader   default_Shader = Shader.Find("TMPro/Bitmap");
                Material tmp_material   = new Material(default_Shader);
                tmp_material.name = tex_FileName + " Material";
                tmp_material.SetTexture(ShaderUtilities.ID_MainTex, m_font_Atlas);
                font_asset.material    = tmp_material;
                tmp_material.hideFlags = HideFlags.HideInHierarchy;
                AssetDatabase.AddObjectToAsset(tmp_material, font_asset);
            }
            else
            {
                // Find all Materials referencing this font atlas.
                Material[] material_references = TMPro_EditorUtility.FindMaterialReferences(font_asset.material);

                // Destroy Assets that will be replaced.
                DestroyImmediate(font_asset.atlas, true);

                // Add FaceInfo to Font Asset
                FaceInfo face = GetFaceInfo(m_font_faceInfo, 1);
                font_asset.AddFaceInfo(face);

                // Add GlyphInfo[] to Font Asset
                GlyphInfo[] glyphs = GetGlyphInfo(m_font_glyphInfo, 1);
                font_asset.AddGlyphInfo(glyphs);

                // Get and Add Kerning Pairs to Font Asset
                if (includeKerningPairs)
                {
                    string       fontFilePath = AssetDatabase.GetAssetPath(font_TTF);
                    KerningTable kerningTable = GetKerningTable(fontFilePath, (int)face.PointSize);
                    font_asset.AddKerningInfo(kerningTable);
                }

                // Add Font Atlas as Sub-Asset
                font_asset.atlas       = m_font_Atlas;
                m_font_Atlas.name      = tex_FileName + " Atlas";
                m_font_Atlas.hideFlags = HideFlags.HideInHierarchy;
                AssetDatabase.AddObjectToAsset(m_font_Atlas, font_asset);

                // Update the Texture reference on the Material
                for (int i = 0; i < material_references.Length; i++)
                {
                    material_references[i].SetTexture(ShaderUtilities.ID_MainTex, font_asset.atlas);
                }
            }
            AssetDatabase.SaveAssets();

            AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(font_asset));  // Re-import font asset to get the new updated version.

            //EditorUtility.SetDirty(font_asset);
            font_asset.ReadFontDefinition();

            AssetDatabase.Refresh();

            // NEED TO GENERATE AN EVENT TO FORCE A REDRAW OF ANY TEXTMESHPRO INSTANCES THAT MIGHT BE USING THIS FONT ASSET
            TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, font_asset);
        }