diff options
author | chai <chaifix@163.com> | 2021-05-08 23:15:13 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2021-05-08 23:15:13 +0800 |
commit | d07e14add74e017b52ab2371efeea1aa4ea10ced (patch) | |
tree | efd07869326e4c428f5bfe43fad0c2583d32a401 /Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font |
+init
Diffstat (limited to 'Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font')
6 files changed, 842 insertions, 0 deletions
diff --git a/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/FontData.cs b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/FontData.cs new file mode 100644 index 0000000..3a85af1 --- /dev/null +++ b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/FontData.cs @@ -0,0 +1,158 @@ +using System; +using UnityEngine.Serialization; + +namespace UnityEngine.UI +{ + /// <summary> + /// Labels reference specific font data used to draw them. This class contains that data. + /// </summary> + + [Serializable] + public class FontData : ISerializationCallbackReceiver + { + [SerializeField] + [FormerlySerializedAs("font")] + private Font m_Font; + + [SerializeField] + [FormerlySerializedAs("fontSize")] + private int m_FontSize; + + [SerializeField] + [FormerlySerializedAs("fontStyle")] + private FontStyle m_FontStyle; + + [SerializeField] + private bool m_BestFit; + + [SerializeField] + private int m_MinSize; + + [SerializeField] + private int m_MaxSize; + + [SerializeField] + [FormerlySerializedAs("alignment")] + private TextAnchor m_Alignment; + + [SerializeField] + private bool m_AlignByGeometry; + + [SerializeField] + [FormerlySerializedAs("richText")] + private bool m_RichText; + + [SerializeField] + private HorizontalWrapMode m_HorizontalOverflow; + + [SerializeField] + private VerticalWrapMode m_VerticalOverflow; + + [SerializeField] + private float m_LineSpacing; + + public static FontData defaultFontData + { + get + { + var fontData = new FontData + { + m_FontSize = 14, + m_LineSpacing = 1f, + m_FontStyle = FontStyle.Normal, + m_BestFit = false, + m_MinSize = 10, + m_MaxSize = 40, + m_Alignment = TextAnchor.UpperLeft, + m_HorizontalOverflow = HorizontalWrapMode.Wrap, + m_VerticalOverflow = VerticalWrapMode.Truncate, + m_RichText = true, + m_AlignByGeometry = false + }; + return fontData; + } + } + + public Font font + { + get { return m_Font; } + set { m_Font = value; } + } + + public int fontSize + { + get { return m_FontSize; } + set { Debug.Log("FontData.fontSize"); m_FontSize = value; } + } + + public FontStyle fontStyle + { + get { return m_FontStyle; } + set { m_FontStyle = value; } + } + + public bool bestFit + { + get { return m_BestFit; } + set { m_BestFit = value; } + } + + public int minSize + { + get { return m_MinSize; } + set { m_MinSize = value; } + } + + public int maxSize + { + get { return m_MaxSize; } + set { m_MaxSize = value; } + } + + public TextAnchor alignment + { + get { return m_Alignment; } + set { m_Alignment = value; } + } + + public bool alignByGeometry + { + get { return m_AlignByGeometry; } + set { m_AlignByGeometry = value; } + } + + public bool richText + { + get { return m_RichText; } + set { m_RichText = value; } + } + + public HorizontalWrapMode horizontalOverflow + { + get { return m_HorizontalOverflow; } + set { m_HorizontalOverflow = value; } + } + + public VerticalWrapMode verticalOverflow + { + get { return m_VerticalOverflow; } + set { m_VerticalOverflow = value; } + } + + public float lineSpacing + { + get { return m_LineSpacing; } + set { m_LineSpacing = value; } + } + + void ISerializationCallbackReceiver.OnBeforeSerialize() + {} + + void ISerializationCallbackReceiver.OnAfterDeserialize() + { + m_FontSize = Mathf.Clamp(m_FontSize, 0, 300); + m_MinSize = Mathf.Clamp(m_MinSize, 0, m_FontSize); + m_MaxSize = Mathf.Clamp(m_MaxSize, m_FontSize, 300); + } + } +} diff --git a/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/FontData.cs.meta b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/FontData.cs.meta new file mode 100644 index 0000000..f4bb2a1 --- /dev/null +++ b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/FontData.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 7c47b221885e53f479140fc48712f249 +timeCreated: 1602119379 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/FontUpdateTracker.cs b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/FontUpdateTracker.cs new file mode 100644 index 0000000..a63d62b --- /dev/null +++ b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/FontUpdateTracker.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UnityEngine.UI +{ + // 全局记录使用了某个Font字体的所有Text,当这个Font的GlyphAtlas大小改变的时候通知这些Text重建mesh(更新UV) + // 因为GlyphAtlas大小改变了,原先的UV已经不对了 + public static class FontUpdateTracker + { + static Dictionary<Font, HashSet<Text>> m_Tracked = new Dictionary<Font, HashSet<Text>>(); + + public static void TrackText(Text t) + { + if (t.font == null) + return; + + HashSet<Text> exists; + m_Tracked.TryGetValue(t.font, out exists); + if (exists == null) + {
+ // font texture重新生成的时候会调这个回调,然后需要Text组件重建mesh的UV数据,因为原先的fontGlyph里的UV已经不准了
+ // https://docs.unity3d.com/ScriptReference/Font-textureRebuilt.html
+ // The textureRebuilt event is global for all fonts, so we add our delegate the first time we register *any* Text
+ if (m_Tracked.Count == 0) + Font.textureRebuilt += RebuildForFont; + + exists = new HashSet<Text>(); + m_Tracked.Add(t.font, exists); + } + + if (!exists.Contains(t)) + exists.Add(t); + } + + private static void RebuildForFont(Font f) + { + HashSet<Text> texts; + m_Tracked.TryGetValue(f, out texts); + + if (texts == null) + return; + + foreach (var text in texts) + text.FontTextureChanged(); + } + + public static void UntrackText(Text t) + { + if (t.font == null) + return; + + HashSet<Text> texts; + m_Tracked.TryGetValue(t.font, out texts); + + if (texts == null) + return; + + texts.Remove(t); + + if (texts.Count == 0) + { + m_Tracked.Remove(t.font); + + // There is a global textureRebuilt event for all fonts, so once the last Text reference goes away, remove our delegate + if (m_Tracked.Count == 0) + Font.textureRebuilt -= RebuildForFont; + } + } + } +} diff --git a/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/FontUpdateTracker.cs.meta b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/FontUpdateTracker.cs.meta new file mode 100644 index 0000000..8e6ddeb --- /dev/null +++ b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/FontUpdateTracker.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: fba9c6c6325db2d49bdf2b608066f0e0 +timeCreated: 1602119380 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/Text.cs b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/Text.cs new file mode 100644 index 0000000..3d3d17b --- /dev/null +++ b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/Text.cs @@ -0,0 +1,576 @@ +using System; +using System.Collections.Generic; + +namespace UnityEngine.UI +{ + /// <summary> + /// Labels are graphics that display text. + /// </summary> + + [AddComponentMenu("UI/Text", 10)] + public class Text : MaskableGraphic, ILayoutElement + { + [SerializeField] private FontData m_FontData = FontData.defaultFontData; + +#if UNITY_EDITOR + // needed to track font changes from the inspector + private Font m_LastTrackedFont; +#endif + + [TextArea(3, 10)][SerializeField] protected string m_Text = String.Empty; + + private TextGenerator m_TextCache; + private TextGenerator m_TextCacheForLayout; + + static protected Material s_DefaultText = null; + + // We use this flag instead of Unregistering/Registering the callback to avoid allocation. + [NonSerialized] protected bool m_DisableFontTextureRebuiltCallback = false; + + protected Text() + { + useLegacyMeshGeneration = false; + } + + // text generator,得到字符串在glyph atlas中的UV,构建mesh + /// <summary> + /// Get or set the material used by this Text. + /// </summary> + + public TextGenerator cachedTextGenerator + { + get { return m_TextCache ?? (m_TextCache = (m_Text.Length != 0 ? new TextGenerator(m_Text.Length) : new TextGenerator())); } + } + + public TextGenerator cachedTextGeneratorForLayout + { + get { return m_TextCacheForLayout ?? (m_TextCacheForLayout = new TextGenerator()); } + } + + /// <summary> + /// Text's texture comes from the font. + /// </summary> + public override Texture mainTexture + { + get + { + if (font != null && font.material != null && font.material.mainTexture != null) + return font.material.mainTexture; + + if (m_Material != null) + return m_Material.mainTexture; + + return base.mainTexture; + } + } + + public void FontTextureChanged() + { + // Only invoke if we are not destroyed. + if (!this) + return; + + if (m_DisableFontTextureRebuiltCallback) + return; + + cachedTextGenerator.Invalidate(); + + if (!IsActive()) + return; + + // this is a bit hacky, but it is currently the + // cleanest solution.... + // if we detect the font texture has changed and are in a rebuild loop + // we just regenerate the verts for the new UV's + if (CanvasUpdateRegistry.IsRebuildingGraphics() || CanvasUpdateRegistry.IsRebuildingLayout()) + UpdateGeometry(); + else + SetAllDirty(); + } + + public Font font + { + get + { + return m_FontData.font; + } + set + { + if (m_FontData.font == value) + return; + + FontUpdateTracker.UntrackText(this); + + m_FontData.font = value; + + FontUpdateTracker.TrackText(this); + +#if UNITY_EDITOR + // needed to track font changes from the inspector + m_LastTrackedFont = value; +#endif + + SetAllDirty(); + } + } + + /// <summary> + /// Text that's being displayed by the Text. + /// </summary> + + public virtual string text + { + get + { + return m_Text; + } + set + { + if (String.IsNullOrEmpty(value)) + { + if (String.IsNullOrEmpty(m_Text)) + return; + m_Text = ""; + SetVerticesDirty(); + } + else if (m_Text != value) + { + m_Text = value; + SetVerticesDirty(); + SetLayoutDirty(); + } + } + } + + /// <summary> + /// Whether this Text will support rich text. + /// </summary> + + public bool supportRichText + { + get + { + return m_FontData.richText; + } + set + { + if (m_FontData.richText == value) + return; + m_FontData.richText = value; + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + /// <summary> + /// Wrap mode used by the text. + /// </summary> + + public bool resizeTextForBestFit + { + get + { + return m_FontData.bestFit; + } + set + { + if (m_FontData.bestFit == value) + return; + m_FontData.bestFit = value; + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + public int resizeTextMinSize + { + get + { + return m_FontData.minSize; + } + set + { + if (m_FontData.minSize == value) + return; + m_FontData.minSize = value; + + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + public int resizeTextMaxSize + { + get + { + return m_FontData.maxSize; + } + set + { + if (m_FontData.maxSize == value) + return; + m_FontData.maxSize = value; + + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + /// <summary> + /// Alignment anchor used by the text. + /// </summary> + + public TextAnchor alignment + { + get + { + return m_FontData.alignment; + } + set + { + if (m_FontData.alignment == value) + return; + m_FontData.alignment = value; + + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + public bool alignByGeometry + { + get + { + return m_FontData.alignByGeometry; + } + set + { + if (m_FontData.alignByGeometry == value) + return; + m_FontData.alignByGeometry = value; + + SetVerticesDirty(); + } + } + + public int fontSize + { + get + { + return m_FontData.fontSize; + } + set + { + // font size改变的时候重建mesh + if (m_FontData.fontSize == value) + return; + m_FontData.fontSize = value; + + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + public HorizontalWrapMode horizontalOverflow + { + get + { + return m_FontData.horizontalOverflow; + } + set + { + if (m_FontData.horizontalOverflow == value) + return; + m_FontData.horizontalOverflow = value; + + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + public VerticalWrapMode verticalOverflow + { + get + { + return m_FontData.verticalOverflow; + } + set + { + if (m_FontData.verticalOverflow == value) + return; + m_FontData.verticalOverflow = value; + + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + public float lineSpacing + { + get + { + return m_FontData.lineSpacing; + } + set + { + if (m_FontData.lineSpacing == value) + return; + m_FontData.lineSpacing = value; + + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + /// <summary> + /// Font style used by the Text's text. + /// </summary> + + public FontStyle fontStyle + { + get + { + return m_FontData.fontStyle; + } + set + { + if (m_FontData.fontStyle == value) + return; + m_FontData.fontStyle = value; + + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + public float pixelsPerUnit + { + get + { + var localCanvas = canvas; + if (!localCanvas) + return 1; + // For dynamic fonts, ensure we use one pixel per pixel on the screen. + if (!font || font.dynamic) + return localCanvas.scaleFactor; + // For non-dynamic fonts, calculate pixels per unit based on specified font size relative to font object's own font size. + if (m_FontData.fontSize <= 0 || font.fontSize <= 0) + return 1; + return font.fontSize / (float)m_FontData.fontSize; + } + } + + protected override void OnEnable() + { + base.OnEnable(); + cachedTextGenerator.Invalidate(); + FontUpdateTracker.TrackText(this); + } + + protected override void OnDisable() + { + FontUpdateTracker.UntrackText(this); + base.OnDisable(); + } + + protected override void UpdateGeometry() + { + if (font != null) + { + base.UpdateGeometry(); + } + } + +#if UNITY_EDITOR + protected override void Reset() + { + AssignDefaultFont(); + } + +#endif + internal void AssignDefaultFont() + { + font = Resources.GetBuiltinResource<Font>("Arial.ttf"); + } + + // 根据FontData设置TextGenerationSettings + public TextGenerationSettings GetGenerationSettings(Vector2 extents) + { + var settings = new TextGenerationSettings(); + + settings.generationExtents = extents; + if (font != null && font.dynamic) + { + settings.fontSize = m_FontData.fontSize; + settings.resizeTextMinSize = m_FontData.minSize; + settings.resizeTextMaxSize = m_FontData.maxSize; + } + + // Other settings + settings.textAnchor = m_FontData.alignment; + settings.alignByGeometry = m_FontData.alignByGeometry; + settings.scaleFactor = pixelsPerUnit; + settings.color = color; // 这里是顶点颜色 + settings.font = font; + settings.pivot = rectTransform.pivot; + settings.richText = m_FontData.richText; + settings.lineSpacing = m_FontData.lineSpacing; + settings.fontStyle = m_FontData.fontStyle; + settings.resizeTextForBestFit = m_FontData.bestFit; + settings.updateBounds = false; + settings.horizontalOverflow = m_FontData.horizontalOverflow; + settings.verticalOverflow = m_FontData.verticalOverflow; + + return settings; + } + + static public Vector2 GetTextAnchorPivot(TextAnchor anchor) + { + switch (anchor) + { + case TextAnchor.LowerLeft: return new Vector2(0, 0); + case TextAnchor.LowerCenter: return new Vector2(0.5f, 0); + case TextAnchor.LowerRight: return new Vector2(1, 0); + case TextAnchor.MiddleLeft: return new Vector2(0, 0.5f); + case TextAnchor.MiddleCenter: return new Vector2(0.5f, 0.5f); + case TextAnchor.MiddleRight: return new Vector2(1, 0.5f); + case TextAnchor.UpperLeft: return new Vector2(0, 1); + case TextAnchor.UpperCenter: return new Vector2(0.5f, 1); + case TextAnchor.UpperRight: return new Vector2(1, 1); + default: return Vector2.zero; + } + } + + readonly UIVertex[] m_TempVerts = new UIVertex[4]; + protected override void OnPopulateMesh(VertexHelper toFill) + { + if (font == null) + return; + + // We don't care if we the font Texture changes while we are doing our Update. + // The end result of cachedTextGenerator will be valid for this instance. + // Otherwise we can get issues like Case 619238. + m_DisableFontTextureRebuiltCallback = true; + + Vector2 extents = rectTransform.rect.size; + + // 生成对应的网格数据(顶点、UV) + var settings = GetGenerationSettings(extents); + cachedTextGenerator.PopulateWithErrors(text, settings, gameObject); + + // Apply the offset to the vertices + IList<UIVertex> verts = cachedTextGenerator.verts; + float unitsPerPixel = 1 / pixelsPerUnit; + //Last 4 verts are always a new line... (\n) + int vertCount = verts.Count - 4; + + Vector2 roundingOffset = new Vector2(verts[0].position.x, verts[0].position.y) * unitsPerPixel; + roundingOffset = PixelAdjustPoint(roundingOffset) - roundingOffset; + toFill.Clear(); + if (roundingOffset != Vector2.zero) + { + for (int i = 0; i < vertCount; ++i) + { + int tempVertsIndex = i & 3; + m_TempVerts[tempVertsIndex] = verts[i]; + m_TempVerts[tempVertsIndex].position *= unitsPerPixel; + m_TempVerts[tempVertsIndex].position.x += roundingOffset.x; + m_TempVerts[tempVertsIndex].position.y += roundingOffset.y; + if (tempVertsIndex == 3) + toFill.AddUIVertexQuad(m_TempVerts); + } + } + else + { + for (int i = 0; i < vertCount; ++i) + { + int tempVertsIndex = i & 3; + m_TempVerts[tempVertsIndex] = verts[i]; + m_TempVerts[tempVertsIndex].position *= unitsPerPixel; + if (tempVertsIndex == 3) + toFill.AddUIVertexQuad(m_TempVerts); + } + } + + m_DisableFontTextureRebuiltCallback = false; + } + + public virtual void CalculateLayoutInputHorizontal() {} + public virtual void CalculateLayoutInputVertical() {} + + public virtual float minWidth + { + get { return 0; } + } + + public virtual float preferredWidth + { + get + { + var settings = GetGenerationSettings(Vector2.zero); + return cachedTextGeneratorForLayout.GetPreferredWidth(m_Text, settings) / pixelsPerUnit; + } + } + + public virtual float flexibleWidth { get { return -1; } } + + public virtual float minHeight + { + get { return 0; } + } + + public virtual float preferredHeight + { + get + { + var settings = GetGenerationSettings(new Vector2(GetPixelAdjustedRect().size.x, 0.0f)); + return cachedTextGeneratorForLayout.GetPreferredHeight(m_Text, settings) / pixelsPerUnit; + } + } + + public virtual float flexibleHeight { get { return -1; } } + + public virtual int layoutPriority { get { return 0; } } + +#if UNITY_EDITOR + public override void OnRebuildRequested() + { + // After a Font asset gets re-imported the managed side gets deleted and recreated, + // that means the delegates are not persisted. + // so we need to properly enforce a consistent state here. + FontUpdateTracker.UntrackText(this); + FontUpdateTracker.TrackText(this); + + // Also the textgenerator is no longer valid. + cachedTextGenerator.Invalidate(); + + base.OnRebuildRequested(); + } + + // 当编辑器里修改了参数值的时候调这个回调,setDirty,后续重建mesh + // The Text inspector editor can change the font, and we need a way to track changes so that we get the appropriate rebuild callbacks + // We can intercept changes in OnValidate, and keep track of the previous font reference + protected override void OnValidate() + { + if (!IsActive()) + { + base.OnValidate(); + return; + } + + if (m_FontData.font != m_LastTrackedFont) + { + Font newFont = m_FontData.font; + m_FontData.font = m_LastTrackedFont; + FontUpdateTracker.UntrackText(this); + m_FontData.font = newFont; + FontUpdateTracker.TrackText(this); + + m_LastTrackedFont = newFont; + } + base.OnValidate(); + } + +#endif // if UNITY_EDITOR + } +} diff --git a/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/Text.cs.meta b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/Text.cs.meta new file mode 100644 index 0000000..ea6d1d8 --- /dev/null +++ b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/Text.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 48696ad002dcb2146ab8d6ad72d455d7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: |