From 93d39aa23bfe0b44f8c3812214d2c7fd2da23544 Mon Sep 17 00:00:00 2001 From: DeeNaxic Date: Mon, 24 Apr 2017 22:54:20 +0200 Subject: [PATCH 1/2] Added support for justified text alignment. --- README.md | 1 + Typogenic/Changelog.txt | 4 +- .../01. Different alignments/Demo 01.unity | Bin 17968 -> 20672 bytes Typogenic/Editor/TypogenicTextEditor.cs | 312 ++-- Typogenic/Readme.txt | 17 +- Typogenic/Scripts/TypogenicText.cs | 1490 +++++++++-------- 6 files changed, 961 insertions(+), 863 deletions(-) diff --git a/README.md b/README.md index 0178b13..70bc754 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Contributors - Michael McCollum (gnustoboz) - StarManta + - DeeNaxic License ------- diff --git a/Typogenic/Changelog.txt b/Typogenic/Changelog.txt index 20469ef..78b5c7c 100644 --- a/Typogenic/Changelog.txt +++ b/Typogenic/Changelog.txt @@ -2,9 +2,11 @@ 1.6 - Fixed bugs as a result of Unity API changes. - Changed the folder structure for demos, so they are contained in folders with their related scripts and materials for better modularity. -- Changed the 'Demo 1' to better reflect different alignment options, by adding a right alignment section. +- Changed the 'Demo 1' to better reflect different alignment options, by adding additional sections. - Changed the 'Demo 4' by making the light source move back and fourth, to better show the light effect. - Changed the 'Demo 2' to also show horizontal and vertical gradients. +- Added justified text alignment, and the option for strict justified text alignment. +- Updated the editor inspector for TypogenicText, in order to show the strict setting. - Updated documentation. 1.5 diff --git a/Typogenic/Demos/01. Different alignments/Demo 01.unity b/Typogenic/Demos/01. Different alignments/Demo 01.unity index bc88ff0ab79040c74298e6c60424227e4e3333cb..67d218fd3341cda55bd5bea6738d9efd69ff44e9 100644 GIT binary patch delta 1068 zcmaKq&ubG=5Xa}`SGQHm){>~GkXXe^a}lFP6O&EWN)ZI1NDm$i7^MNhP$TA|Nd+MX zJ;;k#t%rE?M=F)=ACTUPc<8aA~4eDuf0z842`27Wza`2wH3p*{hCFC=h5ihKbz zH$*;8vuyl9>ZainSrc|dklvyW^2guxYuw!9nOZ(zyxM`f|hd3by*3% zAPghu$MuW@_3d4TXTWo21~av%45{);-9ctiWJ=v3W~<1Qx}UxbxnS&cD%fVWf=pF#gW0Oz$)B;YDO=dM@ zD#@E);X9N>-vuy>mXy3@Hiv8t_td63v;1x+$pW)i$dr(G%v{DE>;CbqSAhI_IwwcZ zjLLjeljT^`)i7kn3`!&6m5<_wW!=;gs=1h`*L?ETaFE{{9`vcFy#WN-GS7Kv-mDwR z8P_n)ta{2xyl&bpf21bmL@aDa$)R|p>(tZLpqf+lN7vGSOUnSkWxA{I%GubMwG?j( zv0}|9OgGB=R6xV7I96I#%#N#;lI640c2D&2mZ-=-<46AjejL}% delta 498 zcmYMuJ4ixN90u_J$w&4uZ0I2Q3k!m#I_^sY^t(G&tDQC4^eUqA3c(PSF#( z(Gpov+$m^qD_Uv@8k|}jor9J>^MG&<|MUIM;e5Av$sTr@L=?~yO?io^9eepv`nFoH zl3TBXFAF}HSTspI?;7Af$GawV6>QATpNBF`&wc(# z?x-W>tln8S5*=cqg^qrIW3G?D5KQjK4dWEH72gvB6K4E08m)!h%)^J1$Y!kEE zQ4sb6`=ns4n6BP)bMH(AsXI2uqw%)}3Ueuu{y$I?6}G|mlD 0f) - { - Vector3 alignmentOffset = Vector3.zero; - if (src.Alignment == TTextAlignment.Center) alignmentOffset = new Vector3(-src.WordWrap * 0.5f, 0f, 0f); - else if (src.Alignment == TTextAlignment.Right) alignmentOffset = new Vector3(-src.WordWrap, 0f, 0f); - - Vector3 v1 = src.transform.TransformPoint(alignmentOffset); - Vector3 v2 = src.transform.TransformPoint(alignmentOffset + new Vector3(src.WordWrap, 0f, 0f)); - Vector3 v3 = src.transform.TransformPoint(alignmentOffset + new Vector3(0f, -src.Height, 0f)); - Vector3 v4 = src.transform.TransformPoint(alignmentOffset + new Vector3(src.WordWrap, -src.Height, 0f)); - - Handles.color = Color.yellow; - Handles.DrawLine(v1, v2); - Handles.DrawLine(v1, v3); - Handles.DrawLine(v4, v3); - Handles.DrawLine(v2, v4); - } - } - - [MenuItem("GameObject/Create Other/Typogenic Text", false, 1500)] - public static void CreateNewTypogenicText() - { - GameObject gameObject = new GameObject("New Typogenic Text"); - gameObject.AddComponent(); - #if (UNITY_4_3 || UNITY_4_5 || UNITY_4_6) - gameObject.GetComponent().castShadows = false; - #else - gameObject.GetComponent().shadowCastingMode = ShadowCastingMode.Off; - #endif - gameObject.GetComponent().receiveShadows = false; - Selection.objects = new GameObject[1] { gameObject }; - EditorApplication.ExecuteMenuItem("GameObject/Move To View"); - - #if UNITY_3_4 || UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 - #else - Undo.RegisterCreatedObjectUndo(gameObject, "Created New Typogenic Text"); - #endif - } + protected SerializedProperty m_Font; + protected SerializedProperty m_Text; + protected SerializedProperty m_Size; + protected SerializedProperty m_Leading; + protected SerializedProperty m_Tracking; + protected SerializedProperty m_ParagraphSpacing; + protected SerializedProperty m_WordWrap; + protected SerializedProperty m_Alignment; + protected SerializedProperty m_JustifiedStrict; + protected SerializedProperty m_FillMode; + protected SerializedProperty m_ColorTopLeft; + protected SerializedProperty m_ColorTopRight; + protected SerializedProperty m_ColorBottomLeft; + protected SerializedProperty m_ColorBottomRight; + protected SerializedProperty m_GenerateNormals; + protected SerializedProperty m_Stationary; + protected SerializedProperty m_EnableClickSupport; + protected SerializedProperty m_DrawGlyphBoundsGizmos; + + Vector2 scrollText; + + void OnEnable() + { + m_Font = serializedObject.FindProperty("Font"); + m_Text = serializedObject.FindProperty("Text"); + m_Size = serializedObject.FindProperty("Size"); + m_Leading = serializedObject.FindProperty("Leading"); + m_Tracking = serializedObject.FindProperty("Tracking"); + m_ParagraphSpacing = serializedObject.FindProperty("ParagraphSpacing"); + m_WordWrap = serializedObject.FindProperty("WordWrap"); + m_Alignment = serializedObject.FindProperty("Alignment"); + m_JustifiedStrict = serializedObject.FindProperty("JustifiedStrict"); + m_FillMode = serializedObject.FindProperty("FillMode"); + m_ColorTopLeft = serializedObject.FindProperty("ColorTopLeft"); + m_ColorTopRight = serializedObject.FindProperty("ColorTopRight"); + m_ColorBottomLeft = serializedObject.FindProperty("ColorBottomLeft"); + m_ColorBottomRight = serializedObject.FindProperty("ColorBottomRight"); + m_GenerateNormals = serializedObject.FindProperty("GenerateNormals"); + m_Stationary = serializedObject.FindProperty("Stationary"); + m_EnableClickSupport = serializedObject.FindProperty("EnableClickSupport"); + m_DrawGlyphBoundsGizmos = serializedObject.FindProperty("DrawGlyphBoundsGizmos"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + /* + * This method has been deprecated: + * + * EditorGUIUtility.LookLikeControls(); + */ + + EditorGUILayout.PropertyField(m_Font); + EditorGUILayout.PropertyField(m_GenerateNormals); + EditorGUILayout.PropertyField(m_EnableClickSupport); + + if (m_EnableClickSupport.boolValue) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_DrawGlyphBoundsGizmos); + EditorGUILayout.PropertyField(m_Stationary, new GUIContent("Static")); + EditorGUI.indentLevel--; + } + + EditorGUILayout.PrefixLabel(String.Format("Text (w: {0:F2}, h: {1:F2})", ((TypogenicText)target).Width, ((TypogenicText)target).Height)); + scrollText = EditorGUILayout.BeginScrollView(scrollText, GUILayout.MinHeight(85f), GUILayout.MaxHeight(200f)); + m_Text.stringValue = EditorGUILayout.TextArea(m_Text.stringValue, GUILayout.MinHeight(85f), GUILayout.MaxHeight(200f)); + EditorGUILayout.EndScrollView(); + EditorGUILayout.PropertyField(m_Size, new GUIContent("Character Size")); + EditorGUILayout.PropertyField(m_Tracking, new GUIContent("Character Spacing (Tracking)")); + EditorGUILayout.PropertyField(m_Leading, new GUIContent("Line Spacing (Leading)")); + EditorGUILayout.PropertyField(m_ParagraphSpacing); + EditorGUILayout.PropertyField(m_Alignment); + + /* + * Displays the options for justified text only when justified selected + */ + if (m_Alignment.enumValueIndex == (int)TTextAlignment.Justified) + { + EditorGUILayout.PropertyField(m_JustifiedStrict); + } + + EditorGUILayout.PropertyField(m_WordWrap); + EditorGUILayout.PropertyField(m_FillMode); + + switch (m_FillMode.enumValueIndex) + { + case (int)TFillMode.SingleColor: + EditorGUILayout.PropertyField(m_ColorTopLeft, new GUIContent("Color (RGB + A)")); + break; + case (int)TFillMode.VerticalGradient: + EditorGUILayout.PropertyField(m_ColorTopLeft, new GUIContent("Top Color (RGB + A)")); + EditorGUILayout.PropertyField(m_ColorBottomLeft, new GUIContent("Bottom Color (RGB + A)")); + break; + case (int)TFillMode.HorizontalGradient: + EditorGUILayout.PropertyField(m_ColorTopLeft, new GUIContent("Left Color (RGB + A)")); + EditorGUILayout.PropertyField(m_ColorBottomLeft, new GUIContent("Right Color (RGB + A)")); + break; + case (int)TFillMode.QuadGradient: + EditorGUILayout.PropertyField(m_ColorTopLeft, new GUIContent("Top Left Color (RGB + A)")); + EditorGUILayout.PropertyField(m_ColorTopRight, new GUIContent("Top Right Color (RGB + A)")); + EditorGUILayout.PropertyField(m_ColorBottomLeft, new GUIContent("Bottom Left Color (RGB + A)")); + EditorGUILayout.PropertyField(m_ColorBottomRight, new GUIContent("Bottom Right Color (RGB + A)")); + break; + default: + break; + } + + if (serializedObject.ApplyModifiedProperties() || Event.current.commandName == "UndoRedoPerformed") + { + foreach (TypogenicText t in targets) + { + if (t.enabled && t.gameObject.activeInHierarchy && PrefabUtility.GetPrefabType(target) != PrefabType.Prefab) + t.RebuildMesh(); + } + } + } + + void OnSceneGUI() + { + TypogenicText src = (TypogenicText)target; + + if (src.WordWrap > 0f) + { + Vector3 alignmentOffset = Vector3.zero; + if (src.Alignment == TTextAlignment.Center) alignmentOffset = new Vector3(-src.WordWrap * 0.5f, 0f, 0f); + else if (src.Alignment == TTextAlignment.Right) alignmentOffset = new Vector3(-src.WordWrap, 0f, 0f); + + Vector3 v1 = src.transform.TransformPoint(alignmentOffset); + Vector3 v2 = src.transform.TransformPoint(alignmentOffset + new Vector3(src.WordWrap, 0f, 0f)); + Vector3 v3 = src.transform.TransformPoint(alignmentOffset + new Vector3(0f, -src.Height, 0f)); + Vector3 v4 = src.transform.TransformPoint(alignmentOffset + new Vector3(src.WordWrap, -src.Height, 0f)); + + Handles.color = Color.yellow; + Handles.DrawLine(v1, v2); + Handles.DrawLine(v1, v3); + Handles.DrawLine(v4, v3); + Handles.DrawLine(v2, v4); + } + } + + [MenuItem("GameObject/Create Other/Typogenic Text", false, 1500)] + public static void CreateNewTypogenicText() + { + GameObject gameObject = new GameObject("New Typogenic Text"); + gameObject.AddComponent(); + #if (UNITY_4_3 || UNITY_4_5 || UNITY_4_6) + gameObject.GetComponent().castShadows = false; + #else + gameObject.GetComponent().shadowCastingMode = ShadowCastingMode.Off; + #endif + gameObject.GetComponent().receiveShadows = false; + Selection.objects = new GameObject[1] { gameObject }; + EditorApplication.ExecuteMenuItem("GameObject/Move To View"); + + #if UNITY_3_4 || UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 + #else + Undo.RegisterCreatedObjectUndo(gameObject, "Created New Typogenic Text"); + #endif + } } diff --git a/Typogenic/Readme.txt b/Typogenic/Readme.txt index f70ce12..70250a6 100644 --- a/Typogenic/Readme.txt +++ b/Typogenic/Readme.txt @@ -2,17 +2,18 @@ Thanks for downloading Typogenic, I hope it'll fit your needs ! Full documentati Contributors : - * Michael McCollum (gnustoboz) - * StarManta + * Michael McCollum (gnustoboz) + * StarManta + * DeeNaxic If you have any questions or feedback, you can contact me at : - * Twitter: @Chman - * Unity Community: http://forum.unity3d.com/members/15388-Chman + * Twitter: @Chman + * Unity Community: http://forum.unity3d.com/members/15388-Chman Quick links : - * Asset Store : https://www.assetstore.unity3d.com/en/#!/content/19182 - * Github : https://github.com/Chman/Typogenic - * Online Documentation : http://thomashourdel.com/typogenic/doc/ - * Forum : http://forum.unity3d.com/threads/typogenic-advanced-text-rendering-free.254978/ + * Asset Store : https://www.assetstore.unity3d.com/en/#!/content/19182 + * Github : https://github.com/Chman/Typogenic + * Online Documentation : http://thomashourdel.com/typogenic/doc/ + * Forum : http://forum.unity3d.com/threads/typogenic-advanced-text-rendering-free.254978/ diff --git a/Typogenic/Scripts/TypogenicText.cs b/Typogenic/Scripts/TypogenicText.cs index a0aa0f8..b7953be 100644 --- a/Typogenic/Scripts/TypogenicText.cs +++ b/Typogenic/Scripts/TypogenicText.cs @@ -4,19 +4,20 @@ public enum TTextAlignment { - Left, - Center, - Right + Left, + Center, + Right, + Justified } public enum TFillMode { - SingleColor, - VerticalGradient, - HorizontalGradient, - QuadGradient, - ProjectedTexture, - StretchedTexture + SingleColor, + VerticalGradient, + HorizontalGradient, + QuadGradient, + ProjectedTexture, + StretchedTexture } [ExecuteInEditMode] @@ -24,698 +25,781 @@ public enum TFillMode [AddComponentMenu("")] public class TypogenicText : MonoBehaviour { - public TypogenicFont Font; - public string Text = "Hello, World !"; - public float Size = 16.0f; - public float Leading = 0f; - public float Tracking = 0f; - public float ParagraphSpacing = 0f; - public float WordWrap = 0f; - public TTextAlignment Alignment = TTextAlignment.Left; - public TFillMode FillMode = TFillMode.SingleColor; - public Color ColorTopLeft = Color.white; - public Color ColorTopRight = Color.white; - public Color ColorBottomLeft = Color.white; - public Color ColorBottomRight = Color.white; - public bool GenerateNormals = true; - public bool Stationary = true; - public bool EnableClickSupport = true; - - public bool DrawGlyphBoundsGizmos = false; - - public float Width { get; protected set; } - public float Height { get; protected set; } - - public Mesh Mesh { get { return m_Mesh; } } - - protected Mesh m_Mesh; - protected List m_Vertices = new List(); - protected List m_UVs = new List(); - protected List m_UVs2 = new List(); - protected List m_Colors = new List(); - protected List m_GlyphBounds = new List(); - protected List[] m_SubmeshTriangles; - - // Cache components since they are no longer directly exposed: - protected new Renderer renderer; - - // Not the best way to track changes but Unity can't serialize properties, - // so it'll do the job just fine for now. - string _text; - float _size; - float _leading; - float _tracking; - float _paragraphSpacing; - float _wordWrap; - TTextAlignment _alignment; - TFillMode _fillMode; - Color _colorTopLeft; - Color _colorTopRight; - Color _colorBottomLeft; - Color _colorBottomRight; - bool _generateNormals; - bool _stationary; - bool _enableClickSupport; - bool _drawGlyphBoundsGizmos; - int _materialCount; - int _currentMaterial; - - public bool AutoRebuild = true; - public bool IsDirty - { - get - { - if (Text != _text) return true; - else if (Size != _size) return true; - else if (Leading != _leading) return true; - else if (Tracking != _tracking) return true; - else if (ParagraphSpacing != _paragraphSpacing) return true; - else if (WordWrap != _wordWrap) return true; - else if (Alignment != _alignment) return true; - else if (FillMode != _fillMode) return true; - else if (ColorTopLeft != _colorTopLeft) return true; - else if (ColorTopRight != _colorTopRight) return true; - else if (ColorBottomLeft != _colorBottomLeft) return true; - else if (ColorBottomRight != _colorBottomRight) return true; - else if (GenerateNormals != _generateNormals) return true; - else if (Stationary != _stationary) return true; - else if (EnableClickSupport != _enableClickSupport) return true; - - return false; - } - } - - void OnEnable() - { - if (renderer == null) - { - renderer = GetComponent(); - } - - GetComponent().mesh = m_Mesh = new Mesh(); - m_Mesh.name = "Text Mesh"; - m_Mesh.hideFlags = HideFlags.HideAndDontSave; - RebuildMesh(); - } - - void OnDisable() - { - if (Application.isEditor) - { - GetComponent().mesh = null; - DestroyImmediate(m_Mesh); - } - } - - void Reset() - { - RebuildMesh(); - } - - void LateUpdate() - { - if (AutoRebuild && IsDirty) - RebuildMesh(); - } - - public void Set(string text = null, float? size = null, float? leading = null, float? tracking = null, float? paragraphSpacing = null, TTextAlignment? alignement = null, float? wordWrap = null) - { - Text = text ?? Text; - Size = size ?? Size; - Leading = leading ?? Leading; - Tracking = tracking ?? Tracking; - ParagraphSpacing = paragraphSpacing ?? ParagraphSpacing; - Alignment = alignement ?? Alignment; - WordWrap = wordWrap ?? WordWrap; - } - - public void RebuildMesh() - { - if (Font == null) - return; - - _text = Text; - _size = Size; - _leading = Leading; - _tracking = Tracking; - _paragraphSpacing = ParagraphSpacing; - _wordWrap = WordWrap; - _alignment = Alignment; - _fillMode = FillMode; - _colorTopLeft = ColorTopLeft; - _colorTopRight = ColorTopRight; - _colorBottomLeft = ColorBottomLeft; - _colorBottomRight = ColorBottomRight; - _generateNormals = GenerateNormals; - _stationary = Stationary; - _enableClickSupport = EnableClickSupport; - _currentMaterial = 0; - _materialCount = renderer.sharedMaterials.Length; - - m_Mesh.Clear(); - m_Vertices.Clear(); - m_UVs.Clear(); - m_UVs2.Clear(); - m_Colors.Clear(); - - m_SubmeshTriangles = new List[_materialCount]; - - for (int i = 0; i < _materialCount; i++) - m_SubmeshTriangles[i] = new List(); - - if (IsTextNullOrEmpty()) - return; - - ClearGlyphBounds(); - - Width = 0f; - Height = 0f; - float cursorX = 0f, cursorY = 0f; - - Text = Regex.Replace(Text, @"\r\n", "\n"); - string[] lines = Regex.Split(Text, @"\n"); - - if (WordWrap <= 0) - { - foreach (string line in lines) - { - if (Alignment == TTextAlignment.Left) - cursorX = 0f; - else if (Alignment == TTextAlignment.Center) - cursorX = GetStringWidth(line) / -2f; - else if (Alignment == TTextAlignment.Right) - cursorX = -GetStringWidth(line); - - BlitString(line, cursorX, cursorY); - if (EnableClickSupport) - { - AddPlaceholderGlyphBounds(); - } - cursorY += Font.LineHeight * Size + Leading + ParagraphSpacing; - } - } - else - { - List vertexPointers = new List(); - - foreach (string line in lines) - { - string[] words = line.Split(' '); - cursorX = 0; - - foreach (string w in words) - { - string word = w; - - if (Alignment == TTextAlignment.Right) - word = " " + word; - else - word += " "; - - float wordWidth = GetStringWidth(word); - - if (cursorX + wordWidth > WordWrap) - { - OffsetStringPosition(vertexPointers, cursorX); - vertexPointers.Clear(); - - cursorX = 0; - cursorY += Font.LineHeight * Size + Leading; - } - - cursorX = BlitString(word, cursorX, cursorY, vertexPointers); - } - - OffsetStringPosition(vertexPointers, cursorX); - vertexPointers.Clear(); - cursorY += Font.LineHeight * Size + Leading + ParagraphSpacing; - } - } - - Height = cursorY; - - m_Mesh.vertices = m_Vertices.ToArray(); - m_Mesh.uv = m_UVs.ToArray(); - m_Mesh.colors = null; - m_Mesh.uv2 = null; - m_Mesh.normals = null; - - m_Mesh.subMeshCount = renderer.sharedMaterials.Length; - - for (int i = 0; i < m_Mesh.subMeshCount; i++) - m_Mesh.SetTriangles(m_SubmeshTriangles[i].ToArray(), i); - - if (FillMode == TFillMode.StretchedTexture || FillMode == TFillMode.ProjectedTexture) - m_Mesh.uv2 = m_UVs2.ToArray(); - else - m_Mesh.colors = m_Colors.ToArray(); - - if (GenerateNormals) - { - Vector3[] normals = new Vector3[m_Vertices.Count]; - - for (int i = 0; i < m_Vertices.Count; i++) - normals[i] = new Vector3(0f, 0f, -1f); - - m_Mesh.normals = normals; - } - - m_Mesh.RecalculateBounds(); - RefreshColliders(); - } - - void RefreshColliders() - { - foreach (BoxCollider c in GetComponents()) - { - c.size = new Vector3(m_Mesh.bounds.size.x, m_Mesh.bounds.size.y, .1f); - c.center = m_Mesh.bounds.center; - } - } - - bool IsTextNullOrEmpty() - { - if (string.IsNullOrEmpty(Text)) - return true; - - return string.IsNullOrEmpty(Text.Trim()); - } - - float BlitString(string str, float cursorX, float cursorY, List vertexPointers = null) - { - TGlyph prevGlyph = null; - Rect r; - bool inControlCode = false; - int requestedMaterial = 0; - - foreach (char c in str) - { - int charCode = (int)c; - - if (inControlCode) - { - inControlCode = false; - - if (charCode >= 48 && charCode <= 57) // 0-9 - { - requestedMaterial = charCode - 48; - - if (requestedMaterial < _materialCount) - { - _currentMaterial = requestedMaterial; - } - else - { - Debug.LogWarning(string.Format( - "Requested material {0} out of range.", requestedMaterial - )); - } - - if (EnableClickSupport) - { - AddPlaceholderGlyphBounds(); - } - - continue; - } - } - else - { - if (charCode == 92) // Backslash - { - inControlCode = true; - if (EnableClickSupport) - { - AddPlaceholderGlyphBounds(); - } - continue; - } - } - - TGlyph glyph = Font.Glyphs.Get(charCode); - - if (glyph == null) - continue; - - if (charCode == 32) - { - // Assuming here that spaces should not be clickable. - if (EnableClickSupport) - { - AddPlaceholderGlyphBounds(); - } - cursorX += glyph.xAdvance * Size + Tracking; - continue; - } - - float kerning = 0f; - - if (prevGlyph != null) - kerning = prevGlyph.GetKerning(charCode) * Size; - - if (vertexPointers != null) - vertexPointers.Add(m_Vertices.Count); - - r = new Rect( - cursorX + glyph.xOffset * Size + kerning, - cursorY + glyph.yOffset * Size, - glyph.rect.width * Size, - glyph.rect.height * Size - ); - - BlitQuad(r, glyph); - - - // Only need to store glyph bounds if click support is enabled. - if (EnableClickSupport) - { - - // Click bounds for glyphs are based on allocated space, not rendered space. - // Otherwise we'll end up with unclickable dead zones between glyphs. - r.width = glyph.xAdvance * Size; - // And Y coordinates are just not handled the same at all. - r.y = -cursorY - r.height - glyph.yOffset * Size; - - - // Calculate relative world-space bounds for this glyph and store them. - Bounds b = new Bounds( - new Vector3(r.x + r.width/2f, r.y + r.height/2f, 0f), - new Vector3(r.width, r.height, r.height) - ); - - if (Stationary) - { - // Bake the rotation and position into the bounds so we - // don't have to recalculate them on the fly later. - b = TranslateBounds(b); - } - StoreGlyphBounds(b); - } - - - cursorX += glyph.xAdvance * Size + Tracking + kerning; - prevGlyph = glyph; - } - - if (cursorX > Width) - Width = cursorX; - - return cursorX; - } - - float GetStringWidth(string str) - { - TGlyph prevGlyph = null; - bool inControlCode = false; - float width = 0f; - - foreach (char c in str) - { - int charCode = (int)c; - - if (inControlCode) - { - inControlCode = false; - - if (charCode >= 48 && charCode <= 57) // 0-9 - { - continue; - } - } - else - { - if (charCode == 92) // Backslash - { - inControlCode = true; - continue; - } - } - - TGlyph glyph = Font.Glyphs.Get(charCode); - - if (glyph == null) - continue; - - float kerning = 0f; - - if (prevGlyph != null) - kerning = prevGlyph.GetKerning(charCode) * Size; - - width += glyph.xAdvance * Size + Tracking + kerning; - prevGlyph = glyph; - } - - return width; - } - - // Returns the string with line-breaks added everywhere it would wrap - public string GetWrappedText(string text) - { - if(WordWrap <= 0) return text; - - text = Regex.Replace(text, @"\r\n", "\n"); - string[] lines = Regex.Split(text, @"\n"); - - float cursorX = 0f; - - for(int i = 0; i < lines.Length; i++) - { - List words = new List(lines[i].Split(' ')); - cursorX = 0; - - for(int j = 0; j < words.Count; j++) - { - string word = words[j]; - - if (Alignment == TTextAlignment.Right) - word = " " + word; - else - word += " "; - - float wordWidth = GetStringWidth(word); - cursorX += wordWidth; - - if(cursorX > WordWrap) - { - // Wrap this word to the next line - cursorX = wordWidth; - if(j > 0) - words[j - 1] += "\n"; - } - else if(j > 0) - { - words[j - 1] += " "; - } - } - - lines[i] = System.String.Join(System.String.Empty, words.ToArray()); - } - - return System.String.Join("\n", lines); - } - - void OffsetStringPosition(List vertexPointers, float offsetX) - { - if (Alignment == TTextAlignment.Right) - { - foreach (int p in vertexPointers) - { - Vector3 v; - v = m_Vertices[p ]; v.x -= offsetX; m_Vertices[p ] = v; - v = m_Vertices[p + 1]; v.x -= offsetX; m_Vertices[p + 1] = v; - v = m_Vertices[p + 2]; v.x -= offsetX; m_Vertices[p + 2] = v; - v = m_Vertices[p + 3]; v.x -= offsetX; m_Vertices[p + 3] = v; - } - } - else if (Alignment == TTextAlignment.Center) - { - float halfOffsetX = offsetX / 2f; - - foreach (int p in vertexPointers) - { - Vector3 v; - v = m_Vertices[p ]; v.x -= halfOffsetX; m_Vertices[p ] = v; - v = m_Vertices[p + 1]; v.x -= halfOffsetX; m_Vertices[p + 1] = v; - v = m_Vertices[p + 2]; v.x -= halfOffsetX; m_Vertices[p + 2] = v; - v = m_Vertices[p + 3]; v.x -= halfOffsetX; m_Vertices[p + 3] = v; - } - } - } - - void BlitQuad(Rect quad, TGlyph glyph) - { - int index = m_Vertices.Count; - Rect uvs = glyph.rect; - - m_Vertices.Add(new Vector3(quad.x, -quad.y, 0f)); - m_Vertices.Add(new Vector3(quad.x + quad.width, -quad.y, 0f)); - m_Vertices.Add(new Vector3(quad.x + quad.width, -quad.y - quad.height, 0f)); - m_Vertices.Add(new Vector3(quad.x, -quad.y - quad.height, 0f)); - - m_UVs.Add(new Vector2(uvs.x / Font.HScale, 1 - uvs.y / Font.VScale)); - m_UVs.Add(new Vector2((uvs.x + uvs.width) / Font.HScale, 1 - uvs.y / Font.VScale)); - m_UVs.Add(new Vector2((uvs.x + uvs.width) / Font.HScale, 1 - (uvs.y + uvs.height) / Font.VScale)); - m_UVs.Add(new Vector2(uvs.x / Font.HScale, 1 - (uvs.y + uvs.height) / Font.VScale)); - - switch (FillMode) - { - case TFillMode.SingleColor: - m_Colors.Add(ColorTopLeft); - m_Colors.Add(ColorTopLeft); - m_Colors.Add(ColorTopLeft); - m_Colors.Add(ColorTopLeft); - break; - case TFillMode.VerticalGradient: - m_Colors.Add(ColorTopLeft); - m_Colors.Add(ColorTopLeft); - m_Colors.Add(ColorBottomLeft); - m_Colors.Add(ColorBottomLeft); - break; - case TFillMode.HorizontalGradient: - m_Colors.Add(ColorTopLeft); - m_Colors.Add(ColorBottomLeft); - m_Colors.Add(ColorBottomLeft); - m_Colors.Add(ColorTopLeft); - break; - case TFillMode.QuadGradient: - m_Colors.Add(ColorTopLeft); - m_Colors.Add(ColorTopRight); - m_Colors.Add(ColorBottomRight); - m_Colors.Add(ColorBottomLeft); - break; - case TFillMode.StretchedTexture: - m_UVs2.Add(new Vector2(0f, 1f)); - m_UVs2.Add(new Vector2(1f, 1f)); - m_UVs2.Add(new Vector2(1f, 0f)); - m_UVs2.Add(new Vector2(0f, 0f)); - break; - case TFillMode.ProjectedTexture: - float h = uvs.height / Font.LineHeight; - float w = uvs.width / Font.LineHeight; - m_UVs2.Add(new Vector2(glyph.xOffset, h - glyph.yOffset)); - m_UVs2.Add(new Vector2(w - glyph.xOffset, h - glyph.yOffset)); - m_UVs2.Add(new Vector2(w - glyph.xOffset, glyph.yOffset)); - m_UVs2.Add(new Vector2(glyph.xOffset, glyph.yOffset)); - break; - default: - break; - } - - m_SubmeshTriangles[_currentMaterial].Add(index); - m_SubmeshTriangles[_currentMaterial].Add(index + 1); - m_SubmeshTriangles[_currentMaterial].Add(index + 2); - m_SubmeshTriangles[_currentMaterial].Add(index); - m_SubmeshTriangles[_currentMaterial].Add(index + 2); - m_SubmeshTriangles[_currentMaterial].Add(index + 3); - } - - void ClearGlyphBounds() - { - m_GlyphBounds.Clear(); - } - - void StoreGlyphBounds(Bounds b) - { - m_GlyphBounds.Add(b); - } - - Bounds TranslateBounds(Bounds b) - { - Vector3 size; - - b.center = transform.rotation * b.center + transform.position; - size = transform.rotation * b.size; - - // rotating a size by an arbitrary Quaternion can result - // in negative sizes, which will make the bounds checks fail. - size.x = Mathf.Abs(size.x); - size.y = Mathf.Abs(size.y); - size.z = Mathf.Abs(size.z); - - b.size = size; - - return b; - } - - void AddPlaceholderGlyphBounds() - { - // Adds a dummy glyph bounds, to keep the list's indices - // synchronized to the text string's indices. - StoreGlyphBounds(new Bounds()); - } - - int GetGlyphIndexAtWorldPoint(Vector3 point) - { - Bounds b; - - for (int i = 0; i < Text.Length; i++) - { - b = m_GlyphBounds[i]; - - if (!Stationary) - { - b = TranslateBounds(b); - } - - if (b.Contains(point)) - { - return i; - } - } - - return -1; - } - - void OnMouseUpAsButton() - { - if (!EnableClickSupport) - { - return; - } - - Vector3 point; - float distance = 0; - int index = 0; - Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); - Plane p = new Plane(-transform.forward, transform.position); - - if (p.Raycast(ray, out distance)) - { - point = ray.GetPoint(distance); - index = GetGlyphIndexAtWorldPoint(point); - - if (index > -1) - { - BroadcastMessage( - "OnGlyphClicked", - new TypogenicGlyphClickEvent(this, point, index), - SendMessageOptions.DontRequireReceiver - ); - } - } - } - - void OnDrawGizmos() - { - if (!EnableClickSupport) - { - return; - } - - if (DrawGlyphBoundsGizmos) - { - Bounds b; - - Gizmos.color = Color.cyan; - for (int i = 0; i < Text.Length; i++) - { - b = m_GlyphBounds[i]; - if (!Stationary) - { - b = TranslateBounds(b); - } - Gizmos.DrawWireCube(b.center, b.size); - } - } - } + public TypogenicFont Font; + public string Text = "Hello, World !"; + public float Size = 16.0f; + public float Leading = 0f; + public float Tracking = 0f; + public float ParagraphSpacing = 0f; + public float WordWrap = 0f; + public TTextAlignment Alignment = TTextAlignment.Left; + public TFillMode FillMode = TFillMode.SingleColor; + public Color ColorTopLeft = Color.white; + public Color ColorTopRight = Color.white; + public Color ColorBottomLeft = Color.white; + public Color ColorBottomRight = Color.white; + public bool GenerateNormals = true; + public bool Stationary = true; + public bool EnableClickSupport = true; + public bool JustifiedStrict = false; + + public bool DrawGlyphBoundsGizmos = false; + + public float Width { get; protected set; } + public float Height { get; protected set; } + + public Mesh Mesh { get { return m_Mesh; } } + + protected Mesh m_Mesh; + protected List m_Vertices = new List(); + protected List m_UVs = new List(); + protected List m_UVs2 = new List(); + protected List m_Colors = new List(); + protected List m_GlyphBounds = new List(); + protected List[] m_SubmeshTriangles; + + // Cache components since they are no longer directly exposed: + protected new Renderer renderer; + + // Not the best way to track changes but Unity can't serialize properties, + // so it'll do the job just fine for now. + string _text; + float _size; + float _leading; + float _tracking; + float _paragraphSpacing; + float _wordWrap; + TTextAlignment _alignment; + TFillMode _fillMode; + Color _colorTopLeft; + Color _colorTopRight; + Color _colorBottomLeft; + Color _colorBottomRight; + bool _generateNormals; + bool _stationary; + bool _enableClickSupport; + bool _drawGlyphBoundsGizmos; + int _materialCount; + int _currentMaterial; + + public bool AutoRebuild = true; + public bool IsDirty + { + get + { + if (Text != _text) return true; + else if (Size != _size) return true; + else if (Leading != _leading) return true; + else if (Tracking != _tracking) return true; + else if (ParagraphSpacing != _paragraphSpacing) return true; + else if (WordWrap != _wordWrap) return true; + else if (Alignment != _alignment) return true; + else if (FillMode != _fillMode) return true; + else if (ColorTopLeft != _colorTopLeft) return true; + else if (ColorTopRight != _colorTopRight) return true; + else if (ColorBottomLeft != _colorBottomLeft) return true; + else if (ColorBottomRight != _colorBottomRight) return true; + else if (GenerateNormals != _generateNormals) return true; + else if (Stationary != _stationary) return true; + else if (EnableClickSupport != _enableClickSupport) return true; + + return false; + } + } + + void OnEnable() + { + if (renderer == null) + { + renderer = GetComponent(); + } + + GetComponent().mesh = m_Mesh = new Mesh(); + m_Mesh.name = "Text Mesh"; + m_Mesh.hideFlags = HideFlags.HideAndDontSave; + RebuildMesh(); + } + + void OnDisable() + { + if (Application.isEditor) + { + GetComponent().mesh = null; + DestroyImmediate(m_Mesh); + } + } + + void Reset() + { + RebuildMesh(); + } + + void LateUpdate() + { + if (AutoRebuild && IsDirty) + RebuildMesh(); + } + + public void Set(string text = null, float? size = null, float? leading = null, float? tracking = null, float? paragraphSpacing = null, TTextAlignment? alignement = null, float? wordWrap = null) + { + Text = text ?? Text; + Size = size ?? Size; + Leading = leading ?? Leading; + Tracking = tracking ?? Tracking; + ParagraphSpacing = paragraphSpacing ?? ParagraphSpacing; + Alignment = alignement ?? Alignment; + WordWrap = wordWrap ?? WordWrap; + } + + public void RebuildMesh() + { + if (Font == null) + return; + + _text = Text; + _size = Size; + _leading = Leading; + _tracking = Tracking; + _paragraphSpacing = ParagraphSpacing; + _wordWrap = WordWrap; + _alignment = Alignment; + _fillMode = FillMode; + _colorTopLeft = ColorTopLeft; + _colorTopRight = ColorTopRight; + _colorBottomLeft = ColorBottomLeft; + _colorBottomRight = ColorBottomRight; + _generateNormals = GenerateNormals; + _stationary = Stationary; + _enableClickSupport = EnableClickSupport; + _currentMaterial = 0; + _materialCount = renderer.sharedMaterials.Length; + + m_Mesh.Clear(); + m_Vertices.Clear(); + m_UVs.Clear(); + m_UVs2.Clear(); + m_Colors.Clear(); + + m_SubmeshTriangles = new List[_materialCount]; + + for (int i = 0; i < _materialCount; i++) + m_SubmeshTriangles[i] = new List(); + + if (IsTextNullOrEmpty()) + return; + + ClearGlyphBounds(); + + Width = 0f; + Height = 0f; + float cursorX = 0f, cursorY = 0f; + + Text = Regex.Replace(Text, @"\r\n", "\n"); + string[] lines = Regex.Split(Text, @"\n"); + + if (WordWrap < Mathf.Epsilon) + { + foreach (string line in lines) + { + if (Alignment == TTextAlignment.Center) + { + cursorX = -GetStringWidth(line) * 0.50f; + } + else + if (Alignment == TTextAlignment.Right) + { + cursorX = -GetStringWidth(line); + } + else + { + cursorX = 0.00f; + } + + BlitString(line, cursorX, cursorY); + + if (EnableClickSupport) + { + AddPlaceholderGlyphBounds(); + } + + cursorY = cursorY + Font.LineHeight * Size + Leading + ParagraphSpacing; + } + } + else + { + List vertexPointers = new List(); + + foreach (string line in lines) + { + cursorX = 0; + + if (Alignment == TTextAlignment.Justified) + { + List> wordsPerline = new List>(); + List wordsCurrent = new List(); + List wordsPadding = new List(); + + float s = 0.00f; + float n = 0.00f; + + /* + * First we need to figure out how the different words need + * to be split into different lines much like we would have + * done for any other alignment but we also need to get the + * lengths of each of these lines, to use with padding math + */ + foreach (string word in line.Split(' ')) + { + if (s + GetStringWidth(word) > WordWrap) + { + wordsPerline.Add(wordsCurrent); + wordsPadding.Add((WordWrap - s) / (n - 1.00f)); + wordsCurrent = new List + { + word + }; + + s = GetStringWidth(word + " "); + n = 1.00f; + } + else + { + wordsCurrent.Add(word); + + s = s + GetStringWidth(word + " "); + n = n + 1.00f; + } + } + + /* + * Handle the last line as well. If you wanted to do a full + * text justified alignment, this line should be changed to + * add some padding to the last line. But yeah _if_ that is + */ + wordsPerline.Add(wordsCurrent); + + if (JustifiedStrict && n > 1) + { + wordsPadding.Add((WordWrap - s) / (n - 1.00f)); + } + else + { + wordsPadding.Add(0.00f); + } + + /* + * Iterate through, each of the lines, then built them just + * like we would have done normally by adding the linebreak + */ + for (int i = 0; i < wordsPerline.Count; i++) + { + foreach (string word in wordsPerline[i]) + { + cursorX = BlitString(word + " ", cursorX, cursorY, vertexPointers) + wordsPadding[i]; + } + + OffsetStringPosition(vertexPointers, cursorX); + vertexPointers.Clear(); + + cursorX = 0.00f; + cursorY = cursorY + Font.LineHeight * Size + Leading; + } + + cursorY = cursorY + ParagraphSpacing; + } + else + { + /* + * This is the old code, and is run if the alignment is not + * justified. I re-wrote it a bit, but the basic runtime of + * it has not changed. Note the if check is done as were it + * left alignment, as the size is the same for both concats + */ + foreach (string word in line.Split(' ')) + { + if (cursorX + GetStringWidth(word + " ") > WordWrap) + { + OffsetStringPosition(vertexPointers, cursorX); + vertexPointers.Clear(); + + cursorX = 0.00f; + cursorY = cursorY + Font.LineHeight * Size + Leading; + } + + cursorX = BlitString((Alignment == TTextAlignment.Right ? word + " " : " " + word), cursorX, cursorY, vertexPointers); + } + + OffsetStringPosition(vertexPointers, cursorX); + vertexPointers.Clear(); + cursorY = cursorY + Font.LineHeight * Size + Leading + ParagraphSpacing; + } + } + } + + Height = cursorY; + + m_Mesh.vertices = m_Vertices.ToArray(); + m_Mesh.uv = m_UVs.ToArray(); + m_Mesh.colors = null; + m_Mesh.uv2 = null; + m_Mesh.normals = null; + + m_Mesh.subMeshCount = renderer.sharedMaterials.Length; + + for (int i = 0; i < m_Mesh.subMeshCount; i++) + m_Mesh.SetTriangles(m_SubmeshTriangles[i].ToArray(), i); + + if (FillMode == TFillMode.StretchedTexture || FillMode == TFillMode.ProjectedTexture) + m_Mesh.uv2 = m_UVs2.ToArray(); + else + m_Mesh.colors = m_Colors.ToArray(); + + if (GenerateNormals) + { + Vector3[] normals = new Vector3[m_Vertices.Count]; + + for (int i = 0; i < m_Vertices.Count; i++) + normals[i] = new Vector3(0f, 0f, -1f); + + m_Mesh.normals = normals; + } + + m_Mesh.RecalculateBounds(); + RefreshColliders(); + } + + void RefreshColliders() + { + foreach (BoxCollider c in GetComponents()) + { + c.size = new Vector3(m_Mesh.bounds.size.x, m_Mesh.bounds.size.y, .1f); + c.center = m_Mesh.bounds.center; + } + } + + bool IsTextNullOrEmpty() + { + if (string.IsNullOrEmpty(Text)) + return true; + + return string.IsNullOrEmpty(Text.Trim()); + } + + float BlitString(string str, float cursorX, float cursorY, List vertexPointers = null) + { + TGlyph prevGlyph = null; + Rect r; + bool inControlCode = false; + int requestedMaterial = 0; + + foreach (char c in str) + { + int charCode = (int)c; + + if (inControlCode) + { + inControlCode = false; + + if (charCode >= 48 && charCode <= 57) // 0-9 + { + requestedMaterial = charCode - 48; + + if (requestedMaterial < _materialCount) + { + _currentMaterial = requestedMaterial; + } + else + { + Debug.LogWarning(string.Format( + "Requested material {0} out of range.", requestedMaterial + )); + } + + if (EnableClickSupport) + { + AddPlaceholderGlyphBounds(); + } + + continue; + } + } + else + { + if (charCode == 92) // Backslash + { + inControlCode = true; + if (EnableClickSupport) + { + AddPlaceholderGlyphBounds(); + } + continue; + } + } + + TGlyph glyph = Font.Glyphs.Get(charCode); + + if (glyph == null) + continue; + + if (charCode == 32) + { + // Assuming here that spaces should not be clickable. + if (EnableClickSupport) + { + AddPlaceholderGlyphBounds(); + } + cursorX += glyph.xAdvance * Size + Tracking; + continue; + } + + float kerning = 0f; + + if (prevGlyph != null) + kerning = prevGlyph.GetKerning(charCode) * Size; + + if (vertexPointers != null) + vertexPointers.Add(m_Vertices.Count); + + r = new Rect( + cursorX + glyph.xOffset * Size + kerning, + cursorY + glyph.yOffset * Size, + glyph.rect.width * Size, + glyph.rect.height * Size + ); + + BlitQuad(r, glyph); + + + // Only need to store glyph bounds if click support is enabled. + if (EnableClickSupport) + { + + // Click bounds for glyphs are based on allocated space, not rendered space. + // Otherwise we'll end up with unclickable dead zones between glyphs. + r.width = glyph.xAdvance * Size; + // And Y coordinates are just not handled the same at all. + r.y = -cursorY - r.height - glyph.yOffset * Size; + + + // Calculate relative world-space bounds for this glyph and store them. + Bounds b = new Bounds( + new Vector3(r.x + r.width/2f, r.y + r.height/2f, 0f), + new Vector3(r.width, r.height, r.height) + ); + + if (Stationary) + { + // Bake the rotation and position into the bounds so we + // don't have to recalculate them on the fly later. + b = TranslateBounds(b); + } + StoreGlyphBounds(b); + } + + + cursorX += glyph.xAdvance * Size + Tracking + kerning; + prevGlyph = glyph; + } + + if (cursorX > Width) + Width = cursorX; + + return cursorX; + } + + float GetStringWidth(string str) + { + TGlyph prevGlyph = null; + bool inControlCode = false; + float width = 0f; + + foreach (char c in str) + { + int charCode = (int)c; + + if (inControlCode) + { + inControlCode = false; + + if (charCode >= 48 && charCode <= 57) // 0-9 + { + continue; + } + } + else + { + if (charCode == 92) // Backslash + { + inControlCode = true; + continue; + } + } + + TGlyph glyph = Font.Glyphs.Get(charCode); + + if (glyph == null) + continue; + + float kerning = 0f; + + if (prevGlyph != null) + kerning = prevGlyph.GetKerning(charCode) * Size; + + width += glyph.xAdvance * Size + Tracking + kerning; + prevGlyph = glyph; + } + + return width; + } + + // Returns the string with line-breaks added everywhere it would wrap + public string GetWrappedText(string text) + { + if(WordWrap <= 0) return text; + + text = Regex.Replace(text, @"\r\n", "\n"); + string[] lines = Regex.Split(text, @"\n"); + + float cursorX = 0f; + + for(int i = 0; i < lines.Length; i++) + { + List words = new List(lines[i].Split(' ')); + cursorX = 0; + + for(int j = 0; j < words.Count; j++) + { + string word = words[j]; + + if (Alignment == TTextAlignment.Right) + word = " " + word; + else + word += " "; + + float wordWidth = GetStringWidth(word); + cursorX += wordWidth; + + if(cursorX > WordWrap) + { + // Wrap this word to the next line + cursorX = wordWidth; + if(j > 0) + words[j - 1] += "\n"; + } + else if(j > 0) + { + words[j - 1] += " "; + } + } + + lines[i] = System.String.Join(System.String.Empty, words.ToArray()); + } + + return System.String.Join("\n", lines); + } + + void OffsetStringPosition(List vertexPointers, float offsetX) + { + if (Alignment == TTextAlignment.Right) + { + foreach (int p in vertexPointers) + { + Vector3 v; + v = m_Vertices[p ]; v.x -= offsetX; m_Vertices[p ] = v; + v = m_Vertices[p + 1]; v.x -= offsetX; m_Vertices[p + 1] = v; + v = m_Vertices[p + 2]; v.x -= offsetX; m_Vertices[p + 2] = v; + v = m_Vertices[p + 3]; v.x -= offsetX; m_Vertices[p + 3] = v; + } + } + else if (Alignment == TTextAlignment.Center) + { + float halfOffsetX = offsetX / 2f; + + foreach (int p in vertexPointers) + { + Vector3 v; + v = m_Vertices[p ]; v.x -= halfOffsetX; m_Vertices[p ] = v; + v = m_Vertices[p + 1]; v.x -= halfOffsetX; m_Vertices[p + 1] = v; + v = m_Vertices[p + 2]; v.x -= halfOffsetX; m_Vertices[p + 2] = v; + v = m_Vertices[p + 3]; v.x -= halfOffsetX; m_Vertices[p + 3] = v; + } + } + } + + void BlitQuad(Rect quad, TGlyph glyph) + { + int index = m_Vertices.Count; + Rect uvs = glyph.rect; + + m_Vertices.Add(new Vector3(quad.x, -quad.y, 0f)); + m_Vertices.Add(new Vector3(quad.x + quad.width, -quad.y, 0f)); + m_Vertices.Add(new Vector3(quad.x + quad.width, -quad.y - quad.height, 0f)); + m_Vertices.Add(new Vector3(quad.x, -quad.y - quad.height, 0f)); + + m_UVs.Add(new Vector2(uvs.x / Font.HScale, 1 - uvs.y / Font.VScale)); + m_UVs.Add(new Vector2((uvs.x + uvs.width) / Font.HScale, 1 - uvs.y / Font.VScale)); + m_UVs.Add(new Vector2((uvs.x + uvs.width) / Font.HScale, 1 - (uvs.y + uvs.height) / Font.VScale)); + m_UVs.Add(new Vector2(uvs.x / Font.HScale, 1 - (uvs.y + uvs.height) / Font.VScale)); + + switch (FillMode) + { + case TFillMode.SingleColor: + m_Colors.Add(ColorTopLeft); + m_Colors.Add(ColorTopLeft); + m_Colors.Add(ColorTopLeft); + m_Colors.Add(ColorTopLeft); + break; + case TFillMode.VerticalGradient: + m_Colors.Add(ColorTopLeft); + m_Colors.Add(ColorTopLeft); + m_Colors.Add(ColorBottomLeft); + m_Colors.Add(ColorBottomLeft); + break; + case TFillMode.HorizontalGradient: + m_Colors.Add(ColorTopLeft); + m_Colors.Add(ColorBottomLeft); + m_Colors.Add(ColorBottomLeft); + m_Colors.Add(ColorTopLeft); + break; + case TFillMode.QuadGradient: + m_Colors.Add(ColorTopLeft); + m_Colors.Add(ColorTopRight); + m_Colors.Add(ColorBottomRight); + m_Colors.Add(ColorBottomLeft); + break; + case TFillMode.StretchedTexture: + m_UVs2.Add(new Vector2(0f, 1f)); + m_UVs2.Add(new Vector2(1f, 1f)); + m_UVs2.Add(new Vector2(1f, 0f)); + m_UVs2.Add(new Vector2(0f, 0f)); + break; + case TFillMode.ProjectedTexture: + float h = uvs.height / Font.LineHeight; + float w = uvs.width / Font.LineHeight; + m_UVs2.Add(new Vector2(glyph.xOffset, h - glyph.yOffset)); + m_UVs2.Add(new Vector2(w - glyph.xOffset, h - glyph.yOffset)); + m_UVs2.Add(new Vector2(w - glyph.xOffset, glyph.yOffset)); + m_UVs2.Add(new Vector2(glyph.xOffset, glyph.yOffset)); + break; + default: + break; + } + + m_SubmeshTriangles[_currentMaterial].Add(index); + m_SubmeshTriangles[_currentMaterial].Add(index + 1); + m_SubmeshTriangles[_currentMaterial].Add(index + 2); + m_SubmeshTriangles[_currentMaterial].Add(index); + m_SubmeshTriangles[_currentMaterial].Add(index + 2); + m_SubmeshTriangles[_currentMaterial].Add(index + 3); + } + + void ClearGlyphBounds() + { + m_GlyphBounds.Clear(); + } + + void StoreGlyphBounds(Bounds b) + { + m_GlyphBounds.Add(b); + } + + Bounds TranslateBounds(Bounds b) + { + Vector3 size; + + b.center = transform.rotation * b.center + transform.position; + size = transform.rotation * b.size; + + // rotating a size by an arbitrary Quaternion can result + // in negative sizes, which will make the bounds checks fail. + size.x = Mathf.Abs(size.x); + size.y = Mathf.Abs(size.y); + size.z = Mathf.Abs(size.z); + + b.size = size; + + return b; + } + + void AddPlaceholderGlyphBounds() + { + // Adds a dummy glyph bounds, to keep the list's indices + // synchronized to the text string's indices. + StoreGlyphBounds(new Bounds()); + } + + int GetGlyphIndexAtWorldPoint(Vector3 point) + { + Bounds b; + + for (int i = 0; i < Text.Length; i++) + { + b = m_GlyphBounds[i]; + + if (!Stationary) + { + b = TranslateBounds(b); + } + + if (b.Contains(point)) + { + return i; + } + } + + return -1; + } + + void OnMouseUpAsButton() + { + if (!EnableClickSupport) + { + return; + } + + Vector3 point; + float distance = 0; + int index = 0; + Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); + Plane p = new Plane(-transform.forward, transform.position); + + if (p.Raycast(ray, out distance)) + { + point = ray.GetPoint(distance); + index = GetGlyphIndexAtWorldPoint(point); + + if (index > -1) + { + BroadcastMessage( + "OnGlyphClicked", + new TypogenicGlyphClickEvent(this, point, index), + SendMessageOptions.DontRequireReceiver + ); + } + } + } + + void OnDrawGizmos() + { + if (!EnableClickSupport) + { + return; + } + + if (DrawGlyphBoundsGizmos) + { + Bounds b; + + Gizmos.color = Color.cyan; + for (int i = 0; i < Text.Length; i++) + { + b = m_GlyphBounds[i]; + if (!Stationary) + { + b = TranslateBounds(b); + } + Gizmos.DrawWireCube(b.center, b.size); + } + } + } } From 1ee34ff93ecbe481130fcfde769d49442e8a73f3 Mon Sep 17 00:00:00 2001 From: DeeQuation Date: Tue, 11 Jul 2017 21:17:36 +0200 Subject: [PATCH 2/2] Improvements for XHTML/HTML5 specifications. --- Typogenic/Documentation/index.html | 32 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Typogenic/Documentation/index.html b/Typogenic/Documentation/index.html index 136ebce..636e059 100644 --- a/Typogenic/Documentation/index.html +++ b/Typogenic/Documentation/index.html @@ -1,16 +1,16 @@ - - - - - + + + + + Typogenic Documentation - - + +