11using System ;
22using System . Collections . Generic ;
3+ using System . Linq ;
34using UnityEngine ;
45using UnityEngine . EventSystems ;
56using UnityEngine . UI ;
@@ -8,14 +9,7 @@ namespace Hypertext
89{
910 public abstract class HypertextBase : Text , IPointerClickHandler
1011 {
11- Canvas rootCanvas ;
12- Canvas RootCanvas => rootCanvas ?? ( rootCanvas = GetComponentInParent < Canvas > ( ) ) ;
13-
14- const int CharVerts = 6 ;
15- readonly List < Span > spans = new List < Span > ( ) ;
16- static readonly ObjectPool < List < UIVertex > > verticesPool = new ObjectPool < List < UIVertex > > ( null , l => l . Clear ( ) ) ;
17-
18- struct Span
12+ class Span
1913 {
2014 public readonly int StartIndex ;
2115 public readonly int Length ;
@@ -33,6 +27,30 @@ public Span(int startIndex, int endIndex, Color color, Action<string> callback)
3327 }
3428 } ;
3529
30+ readonly List < Span > spans = new List < Span > ( ) ;
31+
32+ // TODO: 頂点が生成されない空白文字をすべて洗い出す
33+ readonly char [ ] invisibleChars =
34+ {
35+ Space ,
36+ Tab ,
37+ LineFeed
38+ } ;
39+ static readonly ObjectPool < List < UIVertex > > verticesPool = new ObjectPool < List < UIVertex > > ( null , l => l . Clear ( ) ) ;
40+
41+ const int CharVerts = 6 ;
42+ const char
43+ Tab = '\t ' ,
44+ LineFeed = '\n ' ,
45+ Space = ' ' ,
46+ LesserThan = '<' ,
47+ GreaterThan = '>' ;
48+
49+ int [ ] visibleCharIndexMap ;
50+
51+ Canvas rootCanvas ;
52+ Canvas RootCanvas => rootCanvas ?? ( rootCanvas = GetComponentInParent < Canvas > ( ) ) ;
53+
3654 /// <summary>
3755 /// 指定した部分文字列にクリックイベントを登録します
3856 /// </summary>
@@ -75,33 +93,98 @@ public virtual void RemoveListeners()
7593 /// </summary>
7694 protected abstract void AddListeners ( ) ;
7795
78- protected override void OnPopulateMesh ( VertexHelper vertexHelper )
96+ readonly UIVertex [ ] tempVerts = new UIVertex [ 4 ] ;
97+ protected override void OnPopulateMesh ( VertexHelper toFill )
7998 {
80- base . OnPopulateMesh ( vertexHelper ) ;
99+ if ( font == null )
100+ {
101+ return ;
102+ }
81103
82- spans . Clear ( ) ;
83- AddListeners ( ) ;
104+ m_DisableFontTextureRebuiltCallback = true ;
105+
106+ var extents = rectTransform . rect . size ;
107+
108+ var settings = GetGenerationSettings ( extents ) ;
109+ settings . generateOutOfBounds = true ;
110+ cachedTextGenerator . PopulateWithErrors ( text , settings , gameObject ) ;
111+
112+ var verts = cachedTextGenerator . verts ;
113+ var unitsPerPixel = 1 / pixelsPerUnit ;
114+ int vertCount = verts . Count ;
115+
116+ if ( vertCount <= 0 )
117+ {
118+ toFill . Clear ( ) ;
119+ return ;
120+ }
121+
122+ var roundingOffset = new Vector2 ( verts [ 0 ] . position . x , verts [ 0 ] . position . y ) * unitsPerPixel ;
123+ roundingOffset = PixelAdjustPoint ( roundingOffset ) - roundingOffset ;
124+ toFill . Clear ( ) ;
125+
126+ if ( roundingOffset != Vector2 . zero )
127+ {
128+ for ( int i = 0 ; i < vertCount ; ++ i )
129+ {
130+ int tempVertsIndex = i & 3 ;
131+ tempVerts [ tempVertsIndex ] = verts [ i ] ;
132+ tempVerts [ tempVertsIndex ] . position *= unitsPerPixel ;
133+ tempVerts [ tempVertsIndex ] . position . x += roundingOffset . x ;
134+ tempVerts [ tempVertsIndex ] . position . y += roundingOffset . y ;
135+
136+ if ( tempVertsIndex == 3 )
137+ {
138+ toFill . AddUIVertexQuad ( tempVerts ) ;
139+ }
140+ }
141+ }
142+ else
143+ {
144+ for ( int i = 0 ; i < vertCount ; ++ i )
145+ {
146+ int tempVertsIndex = i & 3 ;
147+ tempVerts [ tempVertsIndex ] = verts [ i ] ;
148+ tempVerts [ tempVertsIndex ] . position *= unitsPerPixel ;
149+
150+ if ( tempVertsIndex == 3 )
151+ {
152+ toFill . AddUIVertexQuad ( tempVerts ) ;
153+ }
154+ }
155+ }
156+
157+ m_DisableFontTextureRebuiltCallback = false ;
84158
85159 var vertices = verticesPool . Get ( ) ;
86- vertexHelper . GetUIVertexStream ( vertices ) ;
160+ toFill . GetUIVertexStream ( vertices ) ;
87161
88- Modify ( ref vertices ) ;
162+ GenerateVisibleCharIndexMap ( vertices . Count < text . Length * CharVerts ) ;
89163
90- vertexHelper . Clear ( ) ;
91- vertexHelper . AddUIVertexTriangleStream ( vertices ) ;
164+ spans . Clear ( ) ;
165+ AddListeners ( ) ;
166+ GenerateHrefBoundingBoxes ( ref vertices ) ;
167+
168+ toFill . Clear ( ) ;
169+ toFill . AddUIVertexTriangleStream ( vertices ) ;
92170 verticesPool . Release ( vertices ) ;
93171 }
94172
95- void Modify ( ref List < UIVertex > vertices )
173+ void GenerateHrefBoundingBoxes ( ref List < UIVertex > vertices )
96174 {
97175 var verticesCount = vertices . Count ;
98176
99177 for ( var i = 0 ; i < spans . Count ; i ++ )
100178 {
101179 var span = spans [ i ] ;
102- var endIndex = span . StartIndex + span . Length ;
103180
104- for ( var textIndex = span . StartIndex ; textIndex < endIndex ; textIndex ++ )
181+ var startIndex = visibleCharIndexMap [ span . StartIndex ] ;
182+ var endIndex = visibleCharIndexMap [ span . StartIndex + span . Length - 1 ] ;
183+
184+ startIndex = Mathf . Clamp ( startIndex , 0 , text . Length - 1 ) ;
185+ endIndex = Mathf . Clamp ( endIndex , 0 , text . Length - 1 ) ;
186+
187+ for ( var textIndex = startIndex ; textIndex <= endIndex ; textIndex ++ )
105188 {
106189 var vertexStartIndex = textIndex * CharVerts ;
107190 if ( vertexStartIndex + CharVerts > verticesCount )
@@ -146,7 +229,6 @@ void Modify(ref List<UIVertex> vertices)
146229
147230 // 文字ごとのバウンディングボックスを行ごとのバウンディングボックスにまとめる
148231 span . BoundingBoxes = CalculateLineBoundingBoxes ( span . BoundingBoxes ) ;
149- spans [ i ] = span ;
150232 }
151233 }
152234
@@ -205,6 +287,52 @@ static Rect CalculateAABB(IReadOnlyList<Rect> rects)
205287 return new Rect { min = min , max = max } ;
206288 }
207289
290+ void GenerateVisibleCharIndexMap ( bool verticesReduced )
291+ {
292+ if ( visibleCharIndexMap == null || visibleCharIndexMap . Length < text . Length )
293+ {
294+ Array . Resize ( ref visibleCharIndexMap , text . Length ) ;
295+ }
296+
297+ if ( ! verticesReduced )
298+ {
299+ for ( var i = 0 ; i < visibleCharIndexMap . Length ; i ++ )
300+ {
301+ visibleCharIndexMap [ i ] = i ;
302+ }
303+ return ;
304+ }
305+
306+ var offset = 0 ;
307+ var inTag = false ;
308+
309+ for ( var i = 0 ; i < text . Length ; i ++ )
310+ {
311+ var character = text [ i ] ;
312+
313+ if ( inTag )
314+ {
315+ offset ++ ;
316+
317+ if ( character == GreaterThan )
318+ {
319+ inTag = false ;
320+ }
321+ }
322+ else if ( supportRichText && character == LesserThan )
323+ {
324+ offset ++ ;
325+ inTag = true ;
326+ }
327+ else if ( invisibleChars . Contains ( character ) )
328+ {
329+ offset ++ ;
330+ }
331+
332+ visibleCharIndexMap [ i ] = i - offset ;
333+ }
334+ }
335+
208336 Vector3 CalculateLocalPosition ( Vector3 position , Camera pressEventCamera )
209337 {
210338 if ( ! RootCanvas )
0 commit comments