TMPro_UGUI_Private.cs 234 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610
  1. //#define TMP_PROFILE_ON
  2. using UnityEngine;
  3. using UnityEngine.TextCore;
  4. using System;
  5. using System.Collections.Generic;
  6. using UnityEngine.UI;
  7. using Object = UnityEngine.Object;
  8. #pragma warning disable 0414 // Disabled a few warnings related to serialized variables not used in this script but used in the editor.
  9. #pragma warning disable 0618 // Disabled warning due to SetVertices being deprecated until new release with SetMesh() is available.
  10. namespace TMPro
  11. {
  12. public partial class TextMeshProUGUI
  13. {
  14. [SerializeField]
  15. private bool m_hasFontAssetChanged = false; // Used to track when font properties have changed.
  16. protected TMP_SubMeshUI[] m_subTextObjects = new TMP_SubMeshUI[8];
  17. private float m_previousLossyScaleY = -1; // Used for Tracking lossy scale changes in the transform;
  18. private Vector3[] m_RectTransformCorners = new Vector3[4];
  19. private CanvasRenderer m_canvasRenderer;
  20. private Canvas m_canvas;
  21. private bool m_isFirstAllocation; // Flag to determine if this is the first allocation of the buffers.
  22. private int m_max_characters = 8; // Determines the initial allocation and size of the character array / buffer.
  23. //private int m_max_numberOfLines = 4; // Determines the initial allocation and maximum number of lines of text.
  24. // MASKING RELATED PROPERTIES
  25. // This property is now obsolete and used for compatibility with previous releases (prior to release 0.1.54).
  26. [SerializeField]
  27. private Material m_baseMaterial;
  28. private bool m_isScrollRegionSet;
  29. //private Mask m_mask;
  30. [SerializeField]
  31. private Vector4 m_maskOffset;
  32. // Matrix used to animated Env Map
  33. private Matrix4x4 m_EnvMapMatrix = new Matrix4x4();
  34. //private bool m_isEnabled;
  35. [NonSerialized]
  36. private bool m_isRegisteredForEvents;
  37. protected override void Awake()
  38. {
  39. //Debug.Log("***** Awake() called on object ID " + GetInstanceID() + ". *****");
  40. #if UNITY_EDITOR
  41. // Special handling for TMP Settings and importing Essential Resources
  42. if (TMP_Settings.instance == null)
  43. {
  44. if (m_isWaitingOnResourceLoad == false)
  45. TMPro_EventManager.RESOURCE_LOAD_EVENT.Add(ON_RESOURCES_LOADED);
  46. m_isWaitingOnResourceLoad = true;
  47. return;
  48. }
  49. #endif
  50. // Cache Reference to the Canvas
  51. m_canvas = this.canvas;
  52. m_isOrthographic = true;
  53. // Cache Reference to RectTransform.
  54. m_rectTransform = gameObject.GetComponent<RectTransform>();
  55. if (m_rectTransform == null)
  56. m_rectTransform = gameObject.AddComponent<RectTransform>();
  57. // Cache a reference to the CanvasRenderer.
  58. m_canvasRenderer = GetComponent<CanvasRenderer>();
  59. if (m_canvasRenderer == null)
  60. m_canvasRenderer = gameObject.AddComponent<CanvasRenderer> ();
  61. if (m_mesh == null)
  62. {
  63. m_mesh = new Mesh();
  64. m_mesh.hideFlags = HideFlags.HideAndDontSave;
  65. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  66. m_mesh.name = "TextMeshPro UI Mesh";
  67. #endif
  68. // Create new TextInfo for the text object.
  69. m_textInfo = new TMP_TextInfo(this);
  70. }
  71. // Load TMP Settings for new text object instances.
  72. LoadDefaultSettings();
  73. // Load the font asset and assign material to renderer.
  74. LoadFontAsset();
  75. // Allocate our initial buffers.
  76. if (m_InternalParsingBuffer == null)
  77. m_InternalParsingBuffer = new UnicodeChar[m_max_characters];
  78. m_cached_TextElement = new TMP_Character();
  79. m_isFirstAllocation = true;
  80. // Check to make sure Sub Text Objects are tracked correctly in the event a Prefab is used.
  81. TMP_SubMeshUI[] subTextObjects = GetComponentsInChildren<TMP_SubMeshUI>();
  82. if (subTextObjects.Length > 0)
  83. {
  84. for (int i = 0; i < subTextObjects.Length; i++)
  85. m_subTextObjects[i + 1] = subTextObjects[i];
  86. }
  87. // Set flags to ensure our text is parsed and redrawn.
  88. m_isInputParsingRequired = true;
  89. m_havePropertiesChanged = true;
  90. m_isAwake = true;
  91. }
  92. protected override void OnEnable()
  93. {
  94. //Debug.Log("***** OnEnable() called on object ID " + GetInstanceID() + ". *****");
  95. // Return if Awake() has not been called on the text object.
  96. if (m_isAwake == false)
  97. return;
  98. if (!m_isRegisteredForEvents)
  99. {
  100. //Debug.Log("Registering for Events.");
  101. #if UNITY_EDITOR
  102. // Register Callbacks for various events.
  103. TMPro_EventManager.MATERIAL_PROPERTY_EVENT.Add(ON_MATERIAL_PROPERTY_CHANGED);
  104. TMPro_EventManager.FONT_PROPERTY_EVENT.Add(ON_FONT_PROPERTY_CHANGED);
  105. TMPro_EventManager.TEXTMESHPRO_UGUI_PROPERTY_EVENT.Add(ON_TEXTMESHPRO_UGUI_PROPERTY_CHANGED);
  106. TMPro_EventManager.DRAG_AND_DROP_MATERIAL_EVENT.Add(ON_DRAG_AND_DROP_MATERIAL);
  107. TMPro_EventManager.TEXT_STYLE_PROPERTY_EVENT.Add(ON_TEXT_STYLE_CHANGED);
  108. TMPro_EventManager.COLOR_GRADIENT_PROPERTY_EVENT.Add(ON_COLOR_GRADIENT_CHANGED);
  109. TMPro_EventManager.TMP_SETTINGS_PROPERTY_EVENT.Add(ON_TMP_SETTINGS_CHANGED);
  110. UnityEditor.PrefabUtility.prefabInstanceUpdated += OnPrefabInstanceUpdate;
  111. #endif
  112. m_isRegisteredForEvents = true;
  113. }
  114. // Cache Reference to the Canvas
  115. m_canvas = GetCanvas();
  116. SetActiveSubMeshes(true);
  117. // Register Graphic Component to receive event triggers
  118. GraphicRegistry.RegisterGraphicForCanvas(m_canvas, this);
  119. // Register text object for internal updates
  120. if (m_IsTextObjectScaleStatic == false)
  121. TMP_UpdateManager.RegisterTextObjectForUpdate(this);
  122. ComputeMarginSize();
  123. m_isInputParsingRequired = true;
  124. SetAllDirty();
  125. RecalculateClipping();
  126. RecalculateMasking();
  127. }
  128. protected override void OnDisable()
  129. {
  130. //Debug.Log("***** OnDisable() called on object ID " + GetInstanceID() + ". *****");
  131. // Return if Awake() has not been called on the text object.
  132. if (m_isAwake == false)
  133. return;
  134. //if (m_MaskMaterial != null)
  135. //{
  136. // TMP_MaterialManager.ReleaseStencilMaterial(m_MaskMaterial);
  137. // m_MaskMaterial = null;
  138. //}
  139. // UnRegister Graphic Component
  140. GraphicRegistry.UnregisterGraphicForCanvas(m_canvas, this);
  141. CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild((ICanvasElement)this);
  142. TMP_UpdateManager.UnRegisterTextObjectForUpdate(this);
  143. if (m_canvasRenderer != null)
  144. m_canvasRenderer.Clear();
  145. SetActiveSubMeshes(false);
  146. LayoutRebuilder.MarkLayoutForRebuild(m_rectTransform);
  147. RecalculateClipping();
  148. RecalculateMasking();
  149. }
  150. protected override void OnDestroy()
  151. {
  152. //Debug.Log("***** OnDestroy() called on object ID " + GetInstanceID() + ". *****");
  153. // UnRegister Graphic Component
  154. GraphicRegistry.UnregisterGraphicForCanvas(m_canvas, this);
  155. TMP_UpdateManager.UnRegisterTextObjectForUpdate(this);
  156. // Clean up remaining mesh
  157. if (m_mesh != null)
  158. DestroyImmediate(m_mesh);
  159. // Clean up mask material
  160. if (m_MaskMaterial != null)
  161. {
  162. TMP_MaterialManager.ReleaseStencilMaterial(m_MaskMaterial);
  163. m_MaskMaterial = null;
  164. }
  165. #if UNITY_EDITOR
  166. // Unregister the event this object was listening to
  167. TMPro_EventManager.MATERIAL_PROPERTY_EVENT.Remove(ON_MATERIAL_PROPERTY_CHANGED);
  168. TMPro_EventManager.FONT_PROPERTY_EVENT.Remove(ON_FONT_PROPERTY_CHANGED);
  169. TMPro_EventManager.TEXTMESHPRO_UGUI_PROPERTY_EVENT.Remove(ON_TEXTMESHPRO_UGUI_PROPERTY_CHANGED);
  170. TMPro_EventManager.DRAG_AND_DROP_MATERIAL_EVENT.Remove(ON_DRAG_AND_DROP_MATERIAL);
  171. TMPro_EventManager.TEXT_STYLE_PROPERTY_EVENT.Remove(ON_TEXT_STYLE_CHANGED);
  172. TMPro_EventManager.COLOR_GRADIENT_PROPERTY_EVENT.Remove(ON_COLOR_GRADIENT_CHANGED);
  173. TMPro_EventManager.TMP_SETTINGS_PROPERTY_EVENT.Remove(ON_TMP_SETTINGS_CHANGED);
  174. TMPro_EventManager.RESOURCE_LOAD_EVENT.Remove(ON_RESOURCES_LOADED);
  175. UnityEditor.PrefabUtility.prefabInstanceUpdated -= OnPrefabInstanceUpdate;
  176. #endif
  177. m_isRegisteredForEvents = false;
  178. }
  179. #if UNITY_EDITOR
  180. protected override void Reset()
  181. {
  182. //Debug.Log("***** Reset() *****"); //has been called.");
  183. // Return if Awake() has not been called on the text object.
  184. if (m_isAwake == false)
  185. return;
  186. LoadDefaultSettings();
  187. LoadFontAsset();
  188. m_isInputParsingRequired = true;
  189. m_havePropertiesChanged = true;
  190. }
  191. protected override void OnValidate()
  192. {
  193. //Debug.Log("***** OnValidate() ***** Frame:" + Time.frameCount); // ID " + GetInstanceID()); // New Material [" + m_sharedMaterial.name + "] with ID " + m_sharedMaterial.GetInstanceID() + ". Base Material is [" + m_baseMaterial.name + "] with ID " + m_baseMaterial.GetInstanceID() + ". Previous Base Material is [" + (m_lastBaseMaterial == null ? "Null" : m_lastBaseMaterial.name) + "].");
  194. if (m_isAwake == false)
  195. return;
  196. // Handle Font Asset changes in the inspector.
  197. if (m_fontAsset == null || m_hasFontAssetChanged)
  198. {
  199. LoadFontAsset();
  200. m_hasFontAssetChanged = false;
  201. }
  202. if (m_canvasRenderer == null || m_canvasRenderer.GetMaterial() == null || m_canvasRenderer.GetMaterial().GetTexture(ShaderUtilities.ID_MainTex) == null || m_fontAsset == null || m_fontAsset.atlasTexture.GetInstanceID() != m_canvasRenderer.GetMaterial().GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID())
  203. {
  204. LoadFontAsset();
  205. m_hasFontAssetChanged = false;
  206. }
  207. m_padding = GetPaddingForMaterial();
  208. ComputeMarginSize();
  209. m_isInputParsingRequired = true;
  210. m_inputSource = TextInputSources.Text;
  211. m_havePropertiesChanged = true;
  212. m_isPreferredWidthDirty = true;
  213. m_isPreferredHeightDirty = true;
  214. SetAllDirty();
  215. }
  216. /// <summary>
  217. /// Callback received when Prefabs are updated.
  218. /// </summary>
  219. /// <param name="go">The affected GameObject</param>
  220. void OnPrefabInstanceUpdate(GameObject go)
  221. {
  222. // Remove Callback if this prefab has been deleted.
  223. if (this == null)
  224. {
  225. UnityEditor.PrefabUtility.prefabInstanceUpdated -= OnPrefabInstanceUpdate;
  226. return;
  227. }
  228. if (go == this.gameObject)
  229. {
  230. TMP_SubMeshUI[] subTextObjects = GetComponentsInChildren<TMP_SubMeshUI>();
  231. if (subTextObjects.Length > 0)
  232. {
  233. for (int i = 0; i < subTextObjects.Length; i++)
  234. m_subTextObjects[i + 1] = subTextObjects[i];
  235. }
  236. }
  237. }
  238. // Event received when TMP resources have been loaded.
  239. void ON_RESOURCES_LOADED()
  240. {
  241. TMPro_EventManager.RESOURCE_LOAD_EVENT.Remove(ON_RESOURCES_LOADED);
  242. if (this == null)
  243. return;
  244. Awake();
  245. OnEnable();
  246. }
  247. // Event received when custom material editor properties are changed.
  248. void ON_MATERIAL_PROPERTY_CHANGED(bool isChanged, Material mat)
  249. {
  250. //Debug.Log("ON_MATERIAL_PROPERTY_CHANGED event received."); // Targeted Material is: " + mat.name + " m_sharedMaterial: " + m_sharedMaterial.name + " with ID:" + m_sharedMaterial.GetInstanceID() + " m_renderer.sharedMaterial: " + m_canvasRenderer.GetMaterial() + " Masking Material:" + m_MaskMaterial.GetInstanceID());
  251. ShaderUtilities.GetShaderPropertyIDs(); // Initialize ShaderUtilities and get shader property IDs.
  252. int materialID = mat.GetInstanceID();
  253. int sharedMaterialID = m_sharedMaterial.GetInstanceID();
  254. int maskingMaterialID = m_MaskMaterial == null ? 0 : m_MaskMaterial.GetInstanceID();
  255. if (m_canvasRenderer == null || m_canvasRenderer.GetMaterial() == null)
  256. {
  257. if (m_canvasRenderer == null) return;
  258. if (m_fontAsset != null)
  259. {
  260. m_canvasRenderer.SetMaterial(m_fontAsset.material, m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex));
  261. //Debug.LogWarning("No Material was assigned to " + name + ". " + m_fontAsset.material.name + " was assigned.");
  262. }
  263. else
  264. Debug.LogWarning("No Font Asset assigned to " + name + ". Please assign a Font Asset.", this);
  265. }
  266. if (m_canvasRenderer.GetMaterial() != m_sharedMaterial && m_fontAsset == null) // || m_renderer.sharedMaterials.Contains(mat))
  267. {
  268. //Debug.Log("ON_MATERIAL_PROPERTY_CHANGED Called on Target ID: " + GetInstanceID() + ". Previous Material:" + m_sharedMaterial + " New Material:" + m_uiRenderer.GetMaterial()); // on Object ID:" + GetInstanceID() + ". m_sharedMaterial: " + m_sharedMaterial.name + " m_renderer.sharedMaterial: " + m_renderer.sharedMaterial.name);
  269. m_sharedMaterial = m_canvasRenderer.GetMaterial();
  270. }
  271. // Make sure material properties are synchronized between the assigned material and masking material.
  272. if (m_MaskMaterial != null)
  273. {
  274. UnityEditor.Undo.RecordObject(m_MaskMaterial, "Material Property Changes");
  275. UnityEditor.Undo.RecordObject(m_sharedMaterial, "Material Property Changes");
  276. if (materialID == sharedMaterialID)
  277. {
  278. //Debug.Log("Copy base material properties to masking material if not null.");
  279. float stencilID = m_MaskMaterial.GetFloat(ShaderUtilities.ID_StencilID);
  280. float stencilComp = m_MaskMaterial.GetFloat(ShaderUtilities.ID_StencilComp);
  281. //float stencilOp = m_MaskMaterial.GetFloat(ShaderUtilities.ID_StencilOp);
  282. //float stencilRead = m_MaskMaterial.GetFloat(ShaderUtilities.ID_StencilReadMask);
  283. //float stencilWrite = m_MaskMaterial.GetFloat(ShaderUtilities.ID_StencilWriteMask);
  284. m_MaskMaterial.CopyPropertiesFromMaterial(mat);
  285. m_MaskMaterial.shaderKeywords = mat.shaderKeywords;
  286. m_MaskMaterial.SetFloat(ShaderUtilities.ID_StencilID, stencilID);
  287. m_MaskMaterial.SetFloat(ShaderUtilities.ID_StencilComp, stencilComp);
  288. //m_MaskMaterial.SetFloat(ShaderUtilities.ID_StencilOp, stencilOp);
  289. //m_MaskMaterial.SetFloat(ShaderUtilities.ID_StencilReadMask, stencilID);
  290. //m_MaskMaterial.SetFloat(ShaderUtilities.ID_StencilWriteMask, 0);
  291. }
  292. else if (materialID == maskingMaterialID)
  293. {
  294. // Update the padding
  295. GetPaddingForMaterial(mat);
  296. m_sharedMaterial.CopyPropertiesFromMaterial(mat);
  297. m_sharedMaterial.shaderKeywords = mat.shaderKeywords;
  298. m_sharedMaterial.SetFloat(ShaderUtilities.ID_StencilID, 0);
  299. m_sharedMaterial.SetFloat(ShaderUtilities.ID_StencilComp, 8);
  300. //m_sharedMaterial.SetFloat(ShaderUtilities.ID_StencilOp, 0);
  301. //m_sharedMaterial.SetFloat(ShaderUtilities.ID_StencilReadMask, 255);
  302. //m_sharedMaterial.SetFloat(ShaderUtilities.ID_StencilWriteMask, 255);
  303. }
  304. }
  305. m_padding = GetPaddingForMaterial();
  306. m_havePropertiesChanged = true;
  307. SetVerticesDirty();
  308. //SetMaterialDirty();
  309. }
  310. // Event received when font asset properties are changed in Font Inspector
  311. void ON_FONT_PROPERTY_CHANGED(bool isChanged, Object font)
  312. {
  313. if (MaterialReference.Contains(m_materialReferences, (TMP_FontAsset) font))
  314. {
  315. //Debug.Log("ON_FONT_PROPERTY_CHANGED event received.");
  316. m_isInputParsingRequired = true;
  317. m_havePropertiesChanged = true;
  318. UpdateMeshPadding();
  319. SetLayoutDirty();
  320. SetVerticesDirty();
  321. }
  322. }
  323. // Event received when UNDO / REDO Event alters the properties of the object.
  324. void ON_TEXTMESHPRO_UGUI_PROPERTY_CHANGED(bool isChanged, Object obj)
  325. {
  326. //Debug.Log("Event Received by " + obj);
  327. if (obj == this)
  328. {
  329. //Debug.Log("Undo / Redo Event Received by Object ID:" + GetInstanceID());
  330. m_havePropertiesChanged = true;
  331. m_isInputParsingRequired = true;
  332. ComputeMarginSize(); // Review this change
  333. SetVerticesDirty();
  334. }
  335. }
  336. // Event to Track Material Changed resulting from Drag-n-drop.
  337. void ON_DRAG_AND_DROP_MATERIAL(GameObject obj, Material currentMaterial, Material newMaterial)
  338. {
  339. //Debug.Log("Drag-n-Drop Event - Receiving Object ID " + GetInstanceID() + ". Sender ID " + obj.GetInstanceID()); // + ". Prefab Parent is " + UnityEditor.PrefabUtility.GetPrefabParent(gameObject).GetInstanceID()); // + ". New Material is " + newMaterial.name + " with ID " + newMaterial.GetInstanceID() + ". Base Material is " + m_baseMaterial.name + " with ID " + m_baseMaterial.GetInstanceID());
  340. // Check if event applies to this current object
  341. #if UNITY_2018_2_OR_NEWER
  342. if (obj == gameObject || UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(gameObject) == obj)
  343. #else
  344. if (obj == gameObject || UnityEditor.PrefabUtility.GetPrefabParent(gameObject) == obj)
  345. #endif
  346. {
  347. UnityEditor.Undo.RecordObject(this, "Material Assignment");
  348. UnityEditor.Undo.RecordObject(m_canvasRenderer, "Material Assignment");
  349. m_sharedMaterial = newMaterial;
  350. m_padding = GetPaddingForMaterial();
  351. m_havePropertiesChanged = true;
  352. SetVerticesDirty();
  353. SetMaterialDirty();
  354. }
  355. }
  356. // Event received when Text Styles are changed.
  357. void ON_TEXT_STYLE_CHANGED(bool isChanged)
  358. {
  359. m_havePropertiesChanged = true;
  360. m_isInputParsingRequired = true;
  361. SetVerticesDirty();
  362. }
  363. /// <summary>
  364. /// Event received when a Color Gradient Preset is modified.
  365. /// </summary>
  366. /// <param name="textObject"></param>
  367. void ON_COLOR_GRADIENT_CHANGED(Object gradient)
  368. {
  369. m_havePropertiesChanged = true;
  370. SetVerticesDirty();
  371. }
  372. /// <summary>
  373. /// Event received when the TMP Settings are changed.
  374. /// </summary>
  375. void ON_TMP_SETTINGS_CHANGED()
  376. {
  377. m_defaultSpriteAsset = null;
  378. m_havePropertiesChanged = true;
  379. m_isInputParsingRequired = true;
  380. SetAllDirty();
  381. }
  382. #endif
  383. // Function which loads either the default font or a newly assigned font asset. This function also assigned the appropriate material to the renderer.
  384. protected override void LoadFontAsset()
  385. {
  386. //Debug.Log("***** LoadFontAsset() *****"); //TextMeshPro LoadFontAsset() has been called."); // Current Font Asset is " + (font != null ? font.name: "Null") );
  387. ShaderUtilities.GetShaderPropertyIDs(); // Initialize & Get shader property IDs.
  388. if (m_fontAsset == null)
  389. {
  390. if (TMP_Settings.defaultFontAsset != null)
  391. m_fontAsset = TMP_Settings.defaultFontAsset;
  392. else
  393. m_fontAsset = Resources.Load<TMP_FontAsset>("Fonts & Materials/LiberationSans SDF");
  394. if (m_fontAsset == null)
  395. {
  396. Debug.LogWarning("The LiberationSans SDF Font Asset was not found. There is no Font Asset assigned to " + gameObject.name + ".", this);
  397. return;
  398. }
  399. if (m_fontAsset.characterLookupTable == null)
  400. {
  401. Debug.Log("Dictionary is Null!");
  402. }
  403. m_sharedMaterial = m_fontAsset.material;
  404. }
  405. else
  406. {
  407. // Read font definition if needed.
  408. if (m_fontAsset.characterLookupTable == null)
  409. m_fontAsset.ReadFontAssetDefinition();
  410. // Added for compatibility with previous releases.
  411. if (m_sharedMaterial == null && m_baseMaterial != null)
  412. {
  413. m_sharedMaterial = m_baseMaterial;
  414. m_baseMaterial = null;
  415. }
  416. // If font atlas texture doesn't match the assigned material font atlas, switch back to default material specified in the Font Asset.
  417. if (m_sharedMaterial == null || m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex) == null || m_fontAsset.atlasTexture.GetInstanceID() != m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID())
  418. {
  419. if (m_fontAsset.material == null)
  420. Debug.LogWarning("The Font Atlas Texture of the Font Asset " + m_fontAsset.name + " assigned to " + gameObject.name + " is missing.", this);
  421. else
  422. m_sharedMaterial = m_fontAsset.material;
  423. }
  424. }
  425. // Find and cache Underline & Ellipsis characters.
  426. GetSpecialCharacters(m_fontAsset);
  427. m_padding = GetPaddingForMaterial();
  428. SetMaterialDirty();
  429. }
  430. /// <summary>
  431. /// Method to retrieve the parent Canvas.
  432. /// </summary>
  433. private Canvas GetCanvas()
  434. {
  435. Canvas canvas = null;
  436. var list = TMP_ListPool<Canvas>.Get();
  437. gameObject.GetComponentsInParent(false, list);
  438. if (list.Count > 0)
  439. {
  440. // Find the first active and enabled canvas.
  441. for (int i = 0; i < list.Count; ++i)
  442. {
  443. if (list[i].isActiveAndEnabled)
  444. {
  445. canvas = list[i];
  446. break;
  447. }
  448. }
  449. }
  450. TMP_ListPool<Canvas>.Release(list);
  451. return canvas;
  452. }
  453. /// <summary>
  454. /// Method used when animating the Env Map on the material.
  455. /// </summary>
  456. void UpdateEnvMapMatrix()
  457. {
  458. if (!m_sharedMaterial.HasProperty(ShaderUtilities.ID_EnvMap) || m_sharedMaterial.GetTexture(ShaderUtilities.ID_EnvMap) == null)
  459. return;
  460. //Debug.Log("Updating Env Matrix...");
  461. Vector3 rotation = m_sharedMaterial.GetVector(ShaderUtilities.ID_EnvMatrixRotation);
  462. m_EnvMapMatrix = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(rotation), Vector3.one);
  463. m_sharedMaterial.SetMatrix(ShaderUtilities.ID_EnvMatrix, m_EnvMapMatrix);
  464. }
  465. // Enable Masking in the Shader
  466. void EnableMasking()
  467. {
  468. if (m_fontMaterial == null)
  469. {
  470. m_fontMaterial = CreateMaterialInstance(m_sharedMaterial);
  471. m_canvasRenderer.SetMaterial(m_fontMaterial, m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex));
  472. }
  473. m_sharedMaterial = m_fontMaterial;
  474. if (m_sharedMaterial.HasProperty(ShaderUtilities.ID_ClipRect))
  475. {
  476. m_sharedMaterial.EnableKeyword(ShaderUtilities.Keyword_MASK_SOFT);
  477. m_sharedMaterial.DisableKeyword(ShaderUtilities.Keyword_MASK_HARD);
  478. m_sharedMaterial.DisableKeyword(ShaderUtilities.Keyword_MASK_TEX);
  479. UpdateMask(); // Update Masking Coordinates
  480. }
  481. m_isMaskingEnabled = true;
  482. //m_uiRenderer.SetMaterial(m_sharedMaterial, null);
  483. //m_padding = ShaderUtilities.GetPadding(m_sharedMaterial, m_enableExtraPadding, m_isUsingBold);
  484. //m_alignmentPadding = ShaderUtilities.GetFontExtent(m_sharedMaterial);
  485. /*
  486. Material mat = m_uiRenderer.GetMaterial();
  487. if (mat.HasProperty(ShaderUtilities.ID_MaskCoord))
  488. {
  489. mat.EnableKeyword("MASK_SOFT");
  490. mat.DisableKeyword("MASK_HARD");
  491. mat.DisableKeyword("MASK_OFF");
  492. m_isMaskingEnabled = true;
  493. UpdateMask();
  494. }
  495. */
  496. }
  497. // Enable Masking in the Shader
  498. void DisableMasking()
  499. {
  500. /*
  501. if (m_fontMaterial != null)
  502. {
  503. if (m_stencilID > 0)
  504. m_sharedMaterial = m_MaskMaterial;
  505. else
  506. m_sharedMaterial = m_baseMaterial;
  507. m_canvasRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex));
  508. DestroyImmediate(m_fontMaterial);
  509. }
  510. m_isMaskingEnabled = false;
  511. */
  512. /*
  513. if (m_maskingMaterial != null && m_stencilID == 0)
  514. {
  515. m_sharedMaterial = m_baseMaterial;
  516. m_uiRenderer.SetMaterial(m_sharedMaterial, null);
  517. }
  518. else if (m_stencilID > 0)
  519. {
  520. m_sharedMaterial.EnableKeyword("MASK_OFF");
  521. m_sharedMaterial.DisableKeyword("MASK_HARD");
  522. m_sharedMaterial.DisableKeyword("MASK_SOFT");
  523. }
  524. */
  525. /*
  526. Material mat = m_uiRenderer.GetMaterial();
  527. if (mat.HasProperty(ShaderUtilities.ID_MaskCoord))
  528. {
  529. mat.EnableKeyword("MASK_OFF");
  530. mat.DisableKeyword("MASK_HARD");
  531. mat.DisableKeyword("MASK_SOFT");
  532. m_isMaskingEnabled = false;
  533. UpdateMask();
  534. }
  535. */
  536. }
  537. // Update & recompute Mask offset
  538. void UpdateMask()
  539. {
  540. //Debug.Log("Updating Mask...");
  541. if (m_rectTransform != null)
  542. {
  543. //Material mat = m_uiRenderer.GetMaterial();
  544. //if (mat == null || (m_overflowMode == TextOverflowModes.ScrollRect && m_isScrollRegionSet))
  545. // return;
  546. if (!ShaderUtilities.isInitialized)
  547. ShaderUtilities.GetShaderPropertyIDs();
  548. //Debug.Log("Setting Mask for the first time.");
  549. m_isScrollRegionSet = true;
  550. float softnessX = Mathf.Min(Mathf.Min(m_margin.x, m_margin.z), m_sharedMaterial.GetFloat(ShaderUtilities.ID_MaskSoftnessX));
  551. float softnessY = Mathf.Min(Mathf.Min(m_margin.y, m_margin.w), m_sharedMaterial.GetFloat(ShaderUtilities.ID_MaskSoftnessY));
  552. softnessX = softnessX > 0 ? softnessX : 0;
  553. softnessY = softnessY > 0 ? softnessY : 0;
  554. float width = (m_rectTransform.rect.width - Mathf.Max(m_margin.x, 0) - Mathf.Max(m_margin.z, 0)) / 2 + softnessX;
  555. float height = (m_rectTransform.rect.height - Mathf.Max(m_margin.y, 0) - Mathf.Max(m_margin.w, 0)) / 2 + softnessY;
  556. Vector2 center = m_rectTransform.localPosition + new Vector3((0.5f - m_rectTransform.pivot.x) * m_rectTransform.rect.width + (Mathf.Max(m_margin.x, 0) - Mathf.Max(m_margin.z, 0)) / 2, (0.5f - m_rectTransform.pivot.y) * m_rectTransform.rect.height + (-Mathf.Max(m_margin.y, 0) + Mathf.Max(m_margin.w, 0)) / 2);
  557. //Vector2 center = m_rectTransform.localPosition + new Vector3((0.5f - m_rectTransform.pivot.x) * m_rectTransform.rect.width + (margin.x - margin.z) / 2, (0.5f - m_rectTransform.pivot.y) * m_rectTransform.rect.height + (-margin.y + margin.w) / 2);
  558. Vector4 mask = new Vector4(center.x, center.y, width, height);
  559. //Debug.Log(mask);
  560. //Rect rect = new Rect(0, 0, m_rectTransform.rect.width + margin.x + margin.z, m_rectTransform.rect.height + margin.y + margin.w);
  561. //int softness = (int)m_sharedMaterial.GetFloat(ShaderUtilities.ID_MaskSoftnessX) / 2;
  562. m_sharedMaterial.SetVector(ShaderUtilities.ID_ClipRect, mask);
  563. }
  564. }
  565. // Function called internally when a new material is assigned via the fontMaterial property.
  566. protected override Material GetMaterial(Material mat)
  567. {
  568. // Get Shader PropertyIDs if they haven't been cached already.
  569. ShaderUtilities.GetShaderPropertyIDs();
  570. // Check in case Object is disabled. If so, we don't have a valid reference to the Renderer.
  571. // This can occur when the Duplicate Material Context menu is used on an inactive object.
  572. //if (m_canvasRenderer == null)
  573. // m_canvasRenderer = GetComponent<CanvasRenderer>();
  574. // Create Instance Material only if the new material is not the same instance previously used.
  575. if (m_fontMaterial == null || m_fontMaterial.GetInstanceID() != mat.GetInstanceID())
  576. m_fontMaterial = CreateMaterialInstance(mat);
  577. m_sharedMaterial = m_fontMaterial;
  578. m_padding = GetPaddingForMaterial();
  579. m_ShouldRecalculateStencil = true;
  580. SetVerticesDirty();
  581. SetMaterialDirty();
  582. return m_sharedMaterial;
  583. }
  584. /// <summary>
  585. /// Method returning instances of the materials used by the text object.
  586. /// </summary>
  587. /// <returns></returns>
  588. protected override Material[] GetMaterials(Material[] mats)
  589. {
  590. int materialCount = m_textInfo.materialCount;
  591. if (m_fontMaterials == null)
  592. m_fontMaterials = new Material[materialCount];
  593. else if (m_fontMaterials.Length != materialCount)
  594. TMP_TextInfo.Resize(ref m_fontMaterials, materialCount, false);
  595. // Get instances of the materials
  596. for (int i = 0; i < materialCount; i++)
  597. {
  598. if (i == 0)
  599. m_fontMaterials[i] = fontMaterial;
  600. else
  601. m_fontMaterials[i] = m_subTextObjects[i].material;
  602. }
  603. m_fontSharedMaterials = m_fontMaterials;
  604. return m_fontMaterials;
  605. }
  606. // Function called internally when a new shared material is assigned via the fontSharedMaterial property.
  607. protected override void SetSharedMaterial(Material mat)
  608. {
  609. // Check in case Object is disabled. If so, we don't have a valid reference to the Renderer.
  610. // This can occur when the Duplicate Material Context menu is used on an inactive object.
  611. //if (m_canvasRenderer == null)
  612. // m_canvasRenderer = GetComponent<CanvasRenderer>();
  613. m_sharedMaterial = mat;
  614. m_padding = GetPaddingForMaterial();
  615. SetMaterialDirty();
  616. }
  617. /// <summary>
  618. /// Method returning an array containing the materials used by the text object.
  619. /// </summary>
  620. /// <returns></returns>
  621. protected override Material[] GetSharedMaterials()
  622. {
  623. int materialCount = m_textInfo.materialCount;
  624. if (m_fontSharedMaterials == null)
  625. m_fontSharedMaterials = new Material[materialCount];
  626. else if (m_fontSharedMaterials.Length != materialCount)
  627. TMP_TextInfo.Resize(ref m_fontSharedMaterials, materialCount, false);
  628. for (int i = 0; i < materialCount; i++)
  629. {
  630. if (i == 0)
  631. m_fontSharedMaterials[i] = m_sharedMaterial;
  632. else
  633. m_fontSharedMaterials[i] = m_subTextObjects[i].sharedMaterial;
  634. }
  635. return m_fontSharedMaterials;
  636. }
  637. /// <summary>
  638. /// Method used to assign new materials to the text and sub text objects.
  639. /// </summary>
  640. protected override void SetSharedMaterials(Material[] materials)
  641. {
  642. int materialCount = m_textInfo.materialCount;
  643. // Check allocation of the fontSharedMaterials array.
  644. if (m_fontSharedMaterials == null)
  645. m_fontSharedMaterials = new Material[materialCount];
  646. else if (m_fontSharedMaterials.Length != materialCount)
  647. TMP_TextInfo.Resize(ref m_fontSharedMaterials, materialCount, false);
  648. // Only assign as many materials as the text object contains.
  649. for (int i = 0; i < materialCount; i++)
  650. {
  651. if (i == 0)
  652. {
  653. // Only assign new material if the font atlas textures match.
  654. if (materials[i].GetTexture(ShaderUtilities.ID_MainTex) == null || materials[i].GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID() != m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID())
  655. continue;
  656. m_sharedMaterial = m_fontSharedMaterials[i] = materials[i];
  657. m_padding = GetPaddingForMaterial(m_sharedMaterial);
  658. }
  659. else
  660. {
  661. // Only assign new material if the font atlas textures match.
  662. if (materials[i].GetTexture(ShaderUtilities.ID_MainTex) == null || materials[i].GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID() != m_subTextObjects[i].sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID())
  663. continue;
  664. // Only assign a new material if none were specified in the text input.
  665. if (m_subTextObjects[i].isDefaultMaterial)
  666. m_subTextObjects[i].sharedMaterial = m_fontSharedMaterials[i] = materials[i];
  667. }
  668. }
  669. }
  670. // This function will create an instance of the Font Material.
  671. protected override void SetOutlineThickness(float thickness)
  672. {
  673. // Use material instance if one exists. Otherwise, create a new instance of the shared material.
  674. if (m_fontMaterial != null && m_sharedMaterial.GetInstanceID() != m_fontMaterial.GetInstanceID())
  675. {
  676. m_sharedMaterial = m_fontMaterial;
  677. m_canvasRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex));
  678. }
  679. else if(m_fontMaterial == null)
  680. {
  681. m_fontMaterial = CreateMaterialInstance(m_sharedMaterial);
  682. m_sharedMaterial = m_fontMaterial;
  683. m_canvasRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex));
  684. }
  685. thickness = Mathf.Clamp01(thickness);
  686. m_sharedMaterial.SetFloat(ShaderUtilities.ID_OutlineWidth, thickness);
  687. m_padding = GetPaddingForMaterial();
  688. }
  689. // This function will create an instance of the Font Material.
  690. protected override void SetFaceColor(Color32 color)
  691. {
  692. // Use material instance if one exists. Otherwise, create a new instance of the shared material.
  693. if (m_fontMaterial == null)
  694. m_fontMaterial = CreateMaterialInstance(m_sharedMaterial);
  695. m_sharedMaterial = m_fontMaterial;
  696. m_padding = GetPaddingForMaterial();
  697. m_sharedMaterial.SetColor(ShaderUtilities.ID_FaceColor, color);
  698. }
  699. // This function will create an instance of the Font Material.
  700. protected override void SetOutlineColor(Color32 color)
  701. {
  702. // Use material instance if one exists. Otherwise, create a new instance of the shared material.
  703. if (m_fontMaterial == null)
  704. m_fontMaterial = CreateMaterialInstance(m_sharedMaterial);
  705. m_sharedMaterial = m_fontMaterial;
  706. m_padding = GetPaddingForMaterial();
  707. m_sharedMaterial.SetColor(ShaderUtilities.ID_OutlineColor, color);
  708. }
  709. // Sets the Render Queue and Ztest mode
  710. protected override void SetShaderDepth()
  711. {
  712. if (m_canvas == null || m_sharedMaterial == null)
  713. return;
  714. if (m_canvas.renderMode == RenderMode.ScreenSpaceOverlay || m_isOverlay)
  715. {
  716. // Should this use an instanced material?
  717. m_sharedMaterial.SetFloat(ShaderUtilities.ShaderTag_ZTestMode, 0);
  718. }
  719. else
  720. { // TODO: This section needs to be tested.
  721. m_sharedMaterial.SetFloat(ShaderUtilities.ShaderTag_ZTestMode, 4);
  722. }
  723. }
  724. // Sets the Culling mode of the material
  725. protected override void SetCulling()
  726. {
  727. if (m_isCullingEnabled)
  728. {
  729. Material mat = materialForRendering;
  730. if (mat != null)
  731. mat.SetFloat("_CullMode", 2);
  732. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  733. {
  734. mat = m_subTextObjects[i].materialForRendering;
  735. if (mat != null)
  736. {
  737. mat.SetFloat(ShaderUtilities.ShaderTag_CullMode, 2);
  738. }
  739. }
  740. }
  741. else
  742. {
  743. Material mat = materialForRendering;
  744. if (mat != null)
  745. mat.SetFloat("_CullMode", 0);
  746. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  747. {
  748. mat = m_subTextObjects[i].materialForRendering;
  749. if (mat != null)
  750. {
  751. mat.SetFloat(ShaderUtilities.ShaderTag_CullMode, 0);
  752. }
  753. }
  754. }
  755. }
  756. // Set Perspective Correction Mode based on whether Camera is Orthographic or Perspective
  757. void SetPerspectiveCorrection()
  758. {
  759. if (m_isOrthographic)
  760. m_sharedMaterial.SetFloat(ShaderUtilities.ID_PerspectiveFilter, 0.0f);
  761. else
  762. m_sharedMaterial.SetFloat(ShaderUtilities.ID_PerspectiveFilter, 0.875f);
  763. }
  764. // Function to allocate the necessary buffers to render the text. This function is called whenever the buffer size needs to be increased.
  765. void SetMeshArrays(int size)
  766. {
  767. m_textInfo.meshInfo[0].ResizeMeshInfo(size);
  768. m_canvasRenderer.SetMesh(m_textInfo.meshInfo[0].mesh);
  769. }
  770. // This function parses through the Char[] to determine how many characters will be visible. It then makes sure the arrays are large enough for all those characters.
  771. protected override int SetArraySizes(UnicodeChar[] unicodeChars)
  772. {
  773. #if TMP_PROFILE_ON
  774. Profiler.BeginSample("TMP SetArraySizes()");
  775. //Debug.Log("*** SetArraySizes() ***");
  776. #endif
  777. int spriteCount = 0;
  778. m_totalCharacterCount = 0;
  779. m_isUsingBold = false;
  780. m_isParsingText = false;
  781. tag_NoParsing = false;
  782. m_FontStyleInternal = m_fontStyle;
  783. m_fontStyleStack.Clear();
  784. m_FontWeightInternal = (m_FontStyleInternal & FontStyles.Bold) == FontStyles.Bold ? FontWeight.Bold : m_fontWeight;
  785. m_FontWeightStack.SetDefault(m_FontWeightInternal);
  786. m_currentFontAsset = m_fontAsset;
  787. m_currentMaterial = m_sharedMaterial;
  788. m_currentMaterialIndex = 0;
  789. m_materialReferenceStack.SetDefault(new MaterialReference(m_currentMaterialIndex, m_currentFontAsset, null, m_currentMaterial, m_padding));
  790. m_materialReferenceIndexLookup.Clear();
  791. MaterialReference.AddMaterialReference(m_currentMaterial, m_currentFontAsset, m_materialReferences, m_materialReferenceIndexLookup);
  792. // Set allocations for the text object's TextInfo
  793. if (m_textInfo == null)
  794. m_textInfo = new TMP_TextInfo(m_InternalParsingBufferSize);
  795. else if (m_textInfo.characterInfo.Length < m_InternalParsingBufferSize)
  796. TMP_TextInfo.Resize(ref m_textInfo.characterInfo, m_InternalParsingBufferSize, false);
  797. m_textElementType = TMP_TextElementType.Character;
  798. // Handling for Underline special character
  799. #region Setup Underline Special Character
  800. /*
  801. GetUnderlineSpecialCharacter(m_currentFontAsset);
  802. if (m_Underline.character != null)
  803. {
  804. if (m_Underline.fontAsset.GetInstanceID() != m_currentFontAsset.GetInstanceID())
  805. {
  806. if (TMP_Settings.matchMaterialPreset && m_currentMaterial.GetInstanceID() != m_Underline.fontAsset.material.GetInstanceID())
  807. m_Underline.material = TMP_MaterialManager.GetFallbackMaterial(m_currentMaterial, m_Underline.fontAsset.material);
  808. else
  809. m_Underline.material = m_Underline.fontAsset.material;
  810. m_Underline.materialIndex = MaterialReference.AddMaterialReference(m_Underline.material, m_Underline.fontAsset, m_materialReferences, m_materialReferenceIndexLookup);
  811. m_materialReferences[m_Underline.materialIndex].referenceCount = 0;
  812. }
  813. }
  814. */
  815. #endregion
  816. // Handling for Ellipsis special character
  817. #region Setup Ellipsis Special Character
  818. if (m_overflowMode == TextOverflowModes.Ellipsis)
  819. {
  820. GetEllipsisSpecialCharacter(m_currentFontAsset);
  821. if (m_Ellipsis.character != null)
  822. {
  823. if (m_Ellipsis.fontAsset.GetInstanceID() != m_currentFontAsset.GetInstanceID())
  824. {
  825. if (TMP_Settings.matchMaterialPreset && m_currentMaterial.GetInstanceID() != m_Ellipsis.fontAsset.material.GetInstanceID())
  826. m_Ellipsis.material = TMP_MaterialManager.GetFallbackMaterial(m_currentMaterial, m_Ellipsis.fontAsset.material);
  827. else
  828. m_Ellipsis.material = m_Ellipsis.fontAsset.material;
  829. m_Ellipsis.materialIndex = MaterialReference.AddMaterialReference(m_Ellipsis.material, m_Ellipsis.fontAsset, m_materialReferences, m_materialReferenceIndexLookup);
  830. m_materialReferences[m_Ellipsis.materialIndex].referenceCount = 0;
  831. }
  832. }
  833. else
  834. {
  835. m_overflowMode = TextOverflowModes.Truncate;
  836. if (!TMP_Settings.warningsDisabled)
  837. Debug.LogWarning("The character used for Ellipsis is not available in font asset [" + m_currentFontAsset.name + "] or any potential fallbacks. Switching Text Overflow mode to Truncate.", this);
  838. }
  839. }
  840. #endregion
  841. // Clear Linked Text object if we have one.
  842. if (m_linkedTextComponent != null && !m_isCalculatingPreferredValues)
  843. {
  844. m_linkedTextComponent.text = string.Empty;
  845. m_linkedTextComponent.ClearMesh();
  846. }
  847. // Parsing XML tags in the text
  848. for (int i = 0; i < unicodeChars.Length && unicodeChars[i].unicode != 0; i++)
  849. {
  850. //Make sure the characterInfo array can hold the next text element.
  851. if (m_textInfo.characterInfo == null || m_totalCharacterCount >= m_textInfo.characterInfo.Length)
  852. TMP_TextInfo.Resize(ref m_textInfo.characterInfo, m_totalCharacterCount + 1, true);
  853. int unicode = unicodeChars[i].unicode;
  854. // PARSE XML TAGS
  855. #region PARSE XML TAGS
  856. if (m_isRichText && unicode == 60) // if Char '<'
  857. {
  858. int prev_MaterialIndex = m_currentMaterialIndex;
  859. int endTagIndex;
  860. // Check if Tag is Valid
  861. if (ValidateHtmlTag(unicodeChars, i + 1, out endTagIndex))
  862. {
  863. int tagStartIndex = unicodeChars[i].stringIndex;
  864. i = endTagIndex;
  865. if ((m_FontStyleInternal & FontStyles.Bold) == FontStyles.Bold)
  866. m_isUsingBold = true;
  867. if (m_textElementType == TMP_TextElementType.Sprite)
  868. {
  869. m_materialReferences[m_currentMaterialIndex].referenceCount += 1;
  870. m_textInfo.characterInfo[m_totalCharacterCount].character = (char)(57344 + m_spriteIndex);
  871. m_textInfo.characterInfo[m_totalCharacterCount].spriteIndex = m_spriteIndex;
  872. m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset;
  873. m_textInfo.characterInfo[m_totalCharacterCount].spriteAsset = m_currentSpriteAsset;
  874. m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex;
  875. m_textInfo.characterInfo[m_totalCharacterCount].textElement = m_currentSpriteAsset.spriteCharacterTable[m_spriteIndex];
  876. m_textInfo.characterInfo[m_totalCharacterCount].elementType = m_textElementType;
  877. m_textInfo.characterInfo[m_totalCharacterCount].index = tagStartIndex;
  878. m_textInfo.characterInfo[m_totalCharacterCount].stringLength = unicodeChars[i].stringIndex - tagStartIndex + 1;
  879. // Restore element type and material index to previous values.
  880. m_textElementType = TMP_TextElementType.Character;
  881. m_currentMaterialIndex = prev_MaterialIndex;
  882. spriteCount += 1;
  883. m_totalCharacterCount += 1;
  884. }
  885. continue;
  886. }
  887. }
  888. #endregion
  889. bool isUsingAlternativeTypeface = false;
  890. bool isUsingFallbackOrAlternativeTypeface = false;
  891. TMP_FontAsset prev_fontAsset = m_currentFontAsset;
  892. Material prev_material = m_currentMaterial;
  893. int prev_materialIndex = m_currentMaterialIndex;
  894. // Handle Font Styles like LowerCase, UpperCase and SmallCaps.
  895. #region Handling of LowerCase, UpperCase and SmallCaps Font Styles
  896. if (m_textElementType == TMP_TextElementType.Character)
  897. {
  898. if ((m_FontStyleInternal & FontStyles.UpperCase) == FontStyles.UpperCase)
  899. {
  900. // If this character is lowercase, switch to uppercase.
  901. if (char.IsLower((char)unicode))
  902. unicode = char.ToUpper((char)unicode);
  903. }
  904. else if ((m_FontStyleInternal & FontStyles.LowerCase) == FontStyles.LowerCase)
  905. {
  906. // If this character is uppercase, switch to lowercase.
  907. if (char.IsUpper((char)unicode))
  908. unicode = char.ToLower((char)unicode);
  909. }
  910. else if ((m_FontStyleInternal & FontStyles.SmallCaps) == FontStyles.SmallCaps)
  911. {
  912. // Only convert lowercase characters to uppercase.
  913. if (char.IsLower((char)unicode))
  914. unicode = char.ToUpper((char)unicode);
  915. }
  916. }
  917. #endregion
  918. // Lookup the Glyph data for each character and cache it.
  919. #region LOOKUP GLYPH
  920. TMP_TextElement character = GetTextElement((uint)unicode, m_currentFontAsset, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface);
  921. // Check if Lowercase or Uppercase variant of the character is available.
  922. /* Not sure this is necessary anyone as it is very unlikely with recursive search through fallback fonts.
  923. if (glyph == null)
  924. {
  925. if (char.IsLower((char)c))
  926. {
  927. if (m_currentFontAsset.characterDictionary.TryGetValue(char.ToUpper((char)c), out glyph))
  928. c = chars[i] = char.ToUpper((char)c);
  929. }
  930. else if (char.IsUpper((char)c))
  931. {
  932. if (m_currentFontAsset.characterDictionary.TryGetValue(char.ToLower((char)c), out glyph))
  933. c = chars[i] = char.ToLower((char)c);
  934. }
  935. }*/
  936. // Special handling for missing character.
  937. // Replace missing glyph by the Square (9633) glyph or possibly the Space (32) glyph.
  938. if (character == null)
  939. {
  940. // Save the original unicode character
  941. int srcGlyph = unicode;
  942. // Try replacing the missing glyph character by TMP Settings Missing Glyph or Square (9633) character.
  943. unicode = unicodeChars[i].unicode = TMP_Settings.missingGlyphCharacter == 0 ? 9633 : TMP_Settings.missingGlyphCharacter;
  944. // Check for the missing glyph character in the currently assigned font asset and its fallbacks
  945. character = TMP_FontAssetUtilities.GetCharacterFromFontAsset((uint)unicode, m_currentFontAsset, true, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface);
  946. if (character == null)
  947. {
  948. // Search for the missing glyph character in the TMP Settings Fallback list.
  949. if (TMP_Settings.fallbackFontAssets != null && TMP_Settings.fallbackFontAssets.Count > 0)
  950. character = TMP_FontAssetUtilities.GetCharacterFromFontAssets((uint)unicode, m_currentFontAsset, TMP_Settings.fallbackFontAssets, true, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface);
  951. }
  952. if (character == null)
  953. {
  954. // Search for the missing glyph in the TMP Settings Default Font Asset.
  955. if (TMP_Settings.defaultFontAsset != null)
  956. character = TMP_FontAssetUtilities.GetCharacterFromFontAsset((uint)unicode, TMP_Settings.defaultFontAsset, true, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface);
  957. }
  958. if (character == null)
  959. {
  960. // Use Space (32) Glyph from the currently assigned font asset.
  961. unicode = unicodeChars[i].unicode = 32;
  962. character = TMP_FontAssetUtilities.GetCharacterFromFontAsset((uint)unicode, m_currentFontAsset, true, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface);
  963. }
  964. if (character == null)
  965. {
  966. // Use End of Text (0x03) Glyph from the currently assigned font asset.
  967. unicode = unicodeChars[i].unicode = 0x03;
  968. character = TMP_FontAssetUtilities.GetCharacterFromFontAsset((uint)unicode, m_currentFontAsset, true, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface);
  969. }
  970. if (!TMP_Settings.warningsDisabled)
  971. {
  972. string formattedWarning = srcGlyph > 0xFFFF
  973. ? string.Format("The character with Unicode value \\U{0:X8} was not found in the [{1}] font asset or any potential fallbacks. It was replaced by Unicode character \\u{2:X4} in text object [{3}].", srcGlyph, m_fontAsset.name, character.unicode, this.name)
  974. : string.Format("The character with Unicode value \\u{0:X4} was not found in the [{1}] font asset or any potential fallbacks. It was replaced by Unicode character \\u{2:X4} in text object [{3}].", srcGlyph, m_fontAsset.name, character.unicode, this.name);
  975. Debug.LogWarning(formattedWarning, this);
  976. }
  977. }
  978. if (character.elementType == TextElementType.Character)
  979. {
  980. if (character.textAsset.instanceID != m_currentFontAsset.instanceID)
  981. {
  982. isUsingFallbackOrAlternativeTypeface = true;
  983. m_currentFontAsset = character.textAsset as TMP_FontAsset;
  984. }
  985. }
  986. #endregion
  987. // Save text element data
  988. m_textInfo.characterInfo[m_totalCharacterCount].elementType = TMP_TextElementType.Character;
  989. m_textInfo.characterInfo[m_totalCharacterCount].textElement = character;
  990. m_textInfo.characterInfo[m_totalCharacterCount].isUsingAlternateTypeface = isUsingAlternativeTypeface;
  991. m_textInfo.characterInfo[m_totalCharacterCount].character = (char)unicode;
  992. m_textInfo.characterInfo[m_totalCharacterCount].index = unicodeChars[i].stringIndex;
  993. m_textInfo.characterInfo[m_totalCharacterCount].stringLength = unicodeChars[i].length;
  994. m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset;
  995. // Special handling if the character is a sprite.
  996. if (character.elementType == TextElementType.Sprite)
  997. {
  998. TMP_SpriteAsset spriteAssetRef = character.textAsset as TMP_SpriteAsset;
  999. m_currentMaterialIndex = MaterialReference.AddMaterialReference(spriteAssetRef.material, spriteAssetRef, m_materialReferences, m_materialReferenceIndexLookup);
  1000. m_materialReferences[m_currentMaterialIndex].referenceCount += 1;
  1001. m_textInfo.characterInfo[m_totalCharacterCount].elementType = TMP_TextElementType.Sprite;
  1002. m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex;
  1003. m_textInfo.characterInfo[m_totalCharacterCount].spriteAsset = spriteAssetRef;
  1004. m_textInfo.characterInfo[m_totalCharacterCount].spriteIndex = (int)character.glyphIndex;
  1005. // Restore element type and material index to previous values.
  1006. m_textElementType = TMP_TextElementType.Character;
  1007. m_currentMaterialIndex = prev_materialIndex;
  1008. spriteCount += 1;
  1009. m_totalCharacterCount += 1;
  1010. continue;
  1011. }
  1012. if (isUsingFallbackOrAlternativeTypeface && m_currentFontAsset.instanceID != m_fontAsset.instanceID)
  1013. {
  1014. // Create Fallback material instance matching current material preset if necessary
  1015. if (TMP_Settings.matchMaterialPreset)
  1016. m_currentMaterial = TMP_MaterialManager.GetFallbackMaterial(m_currentMaterial, m_currentFontAsset.material);
  1017. else
  1018. m_currentMaterial = m_currentFontAsset.material;
  1019. m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, m_currentFontAsset, m_materialReferences, m_materialReferenceIndexLookup);
  1020. }
  1021. // Handle Multi Atlas Texture support
  1022. if (character != null && character.glyph.atlasIndex > 0)
  1023. {
  1024. m_currentMaterial = TMP_MaterialManager.GetFallbackMaterial(m_currentFontAsset, m_currentMaterial, character.glyph.atlasIndex);
  1025. m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, m_currentFontAsset, m_materialReferences, m_materialReferenceIndexLookup);
  1026. isUsingFallbackOrAlternativeTypeface = true;
  1027. }
  1028. if (!char.IsWhiteSpace((char)unicode) && unicode != 0x200B)
  1029. {
  1030. // Limit the mesh of the main text object to 65535 vertices and use sub objects for the overflow.
  1031. if (m_materialReferences[m_currentMaterialIndex].referenceCount < 16383)
  1032. m_materialReferences[m_currentMaterialIndex].referenceCount += 1;
  1033. else
  1034. {
  1035. m_currentMaterialIndex = MaterialReference.AddMaterialReference(new Material(m_currentMaterial), m_currentFontAsset, m_materialReferences, m_materialReferenceIndexLookup);
  1036. m_materialReferences[m_currentMaterialIndex].referenceCount += 1;
  1037. }
  1038. }
  1039. m_textInfo.characterInfo[m_totalCharacterCount].material = m_currentMaterial;
  1040. m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex;
  1041. m_materialReferences[m_currentMaterialIndex].isFallbackMaterial = isUsingFallbackOrAlternativeTypeface;
  1042. // Restore previous font asset and material if fallback font was used.
  1043. if (isUsingFallbackOrAlternativeTypeface)
  1044. {
  1045. m_materialReferences[m_currentMaterialIndex].fallbackMaterial = prev_material;
  1046. m_currentFontAsset = prev_fontAsset;
  1047. m_currentMaterial = prev_material;
  1048. m_currentMaterialIndex = prev_materialIndex;
  1049. }
  1050. m_totalCharacterCount += 1;
  1051. }
  1052. // Early return if we are calculating the preferred values.
  1053. if (m_isCalculatingPreferredValues)
  1054. {
  1055. m_isCalculatingPreferredValues = false;
  1056. m_isInputParsingRequired = true;
  1057. return m_totalCharacterCount;
  1058. }
  1059. // Save material and sprite count.
  1060. m_textInfo.spriteCount = spriteCount;
  1061. int materialCount = m_textInfo.materialCount = m_materialReferenceIndexLookup.Count;
  1062. // Check if we need to resize the MeshInfo array for handling different materials.
  1063. if (materialCount > m_textInfo.meshInfo.Length)
  1064. TMP_TextInfo.Resize(ref m_textInfo.meshInfo, materialCount, false);
  1065. // Resize SubTextObject array if necessary
  1066. if (materialCount > m_subTextObjects.Length)
  1067. TMP_TextInfo.Resize(ref m_subTextObjects, Mathf.NextPowerOfTwo(materialCount + 1));
  1068. // Resize CharacterInfo[] if allocations are excessive
  1069. if (m_textInfo.characterInfo.Length - m_totalCharacterCount > 256)
  1070. TMP_TextInfo.Resize(ref m_textInfo.characterInfo, Mathf.Max(m_totalCharacterCount + 1, 256), true);
  1071. // Iterate through the material references to set the mesh buffer allocations
  1072. for (int i = 0; i < materialCount; i++)
  1073. {
  1074. // Add new sub text object for each material reference
  1075. if (i > 0)
  1076. {
  1077. if (m_subTextObjects[i] == null)
  1078. {
  1079. m_subTextObjects[i] = TMP_SubMeshUI.AddSubTextObject(this, m_materialReferences[i]);
  1080. // Not sure this is necessary
  1081. m_textInfo.meshInfo[i].vertices = null;
  1082. }
  1083. //else if (m_subTextObjects[i].gameObject.activeInHierarchy == false)
  1084. // m_subTextObjects[i].gameObject.SetActive(true);
  1085. // Make sure the pivots are synchronized
  1086. if (m_rectTransform.pivot != m_subTextObjects[i].rectTransform.pivot)
  1087. m_subTextObjects[i].rectTransform.pivot = m_rectTransform.pivot;
  1088. // Check if the material has changed.
  1089. if (m_subTextObjects[i].sharedMaterial == null || m_subTextObjects[i].sharedMaterial.GetInstanceID() != m_materialReferences[i].material.GetInstanceID())
  1090. {
  1091. m_subTextObjects[i].sharedMaterial = m_materialReferences[i].material;
  1092. m_subTextObjects[i].fontAsset = m_materialReferences[i].fontAsset;
  1093. m_subTextObjects[i].spriteAsset = m_materialReferences[i].spriteAsset;
  1094. }
  1095. // Check if we need to use a Fallback Material
  1096. if (m_materialReferences[i].isFallbackMaterial)
  1097. {
  1098. m_subTextObjects[i].fallbackMaterial = m_materialReferences[i].material;
  1099. m_subTextObjects[i].fallbackSourceMaterial = m_materialReferences[i].fallbackMaterial;
  1100. }
  1101. }
  1102. int referenceCount = m_materialReferences[i].referenceCount;
  1103. // Check to make sure our buffers allocations can accommodate the required text elements.
  1104. if (m_textInfo.meshInfo[i].vertices == null || m_textInfo.meshInfo[i].vertices.Length < referenceCount * 4)
  1105. {
  1106. if (m_textInfo.meshInfo[i].vertices == null)
  1107. {
  1108. if (i == 0)
  1109. m_textInfo.meshInfo[i] = new TMP_MeshInfo(m_mesh, referenceCount + 1);
  1110. else
  1111. m_textInfo.meshInfo[i] = new TMP_MeshInfo(m_subTextObjects[i].mesh, referenceCount + 1);
  1112. }
  1113. else
  1114. m_textInfo.meshInfo[i].ResizeMeshInfo(referenceCount > 1024 ? referenceCount + 256 : Mathf.NextPowerOfTwo(referenceCount + 1));
  1115. }
  1116. else if (m_VertexBufferAutoSizeReduction && referenceCount > 0 && m_textInfo.meshInfo[i].vertices.Length / 4 - referenceCount > 256)
  1117. {
  1118. // Resize vertex buffers if allocations are excessive.
  1119. //Debug.Log("Reducing the size of the vertex buffers.");
  1120. m_textInfo.meshInfo[i].ResizeMeshInfo(referenceCount > 1024 ? referenceCount + 256 : Mathf.NextPowerOfTwo(referenceCount + 1));
  1121. }
  1122. // Assign material reference
  1123. m_textInfo.meshInfo[i].material = m_materialReferences[i].material;
  1124. }
  1125. //TMP_MaterialManager.CleanupFallbackMaterials();
  1126. // Clean up unused SubMeshes
  1127. for (int i = materialCount; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  1128. {
  1129. if (i < m_textInfo.meshInfo.Length)
  1130. {
  1131. m_subTextObjects[i].canvasRenderer.SetMesh(null);
  1132. // TODO: Figure out a way to handle this without running into Unity's Rebuild loop issue.
  1133. //m_subTextObjects[i].gameObject.SetActive(false);
  1134. }
  1135. }
  1136. #if TMP_PROFILE_ON
  1137. Profiler.EndSample();
  1138. #endif
  1139. return m_totalCharacterCount;
  1140. }
  1141. // Added to sort handle the potential issue with OnWillRenderObject() not getting called when objects are not visible by camera.
  1142. //void OnBecameInvisible()
  1143. //{
  1144. // if (m_mesh != null)
  1145. // m_mesh.bounds = new Bounds(transform.position, new Vector3(1000, 1000, 0));
  1146. //}
  1147. /// <summary>
  1148. /// Update the margin width and height
  1149. /// </summary>
  1150. public override void ComputeMarginSize()
  1151. {
  1152. if (this.rectTransform != null)
  1153. {
  1154. //Debug.Log("*** ComputeMarginSize() *** Current RectTransform's Width is " + m_rectTransform.rect.width + " and Height is " + m_rectTransform.rect.height); // + " and size delta is " + m_rectTransform.sizeDelta);
  1155. Rect rect = m_rectTransform.rect;
  1156. m_marginWidth = rect.width - m_margin.x - m_margin.z;
  1157. m_marginHeight = rect.height - m_margin.y - m_margin.w;
  1158. // Cache current RectTransform width and pivot referenced in OnRectTransformDimensionsChange() to get around potential rounding error in the reported width of the RectTransform.
  1159. m_PreviousRectTransformSize = rect.size;
  1160. m_PreviousPivotPosition = m_rectTransform.pivot;
  1161. // Update the corners of the RectTransform
  1162. m_RectTransformCorners = GetTextContainerLocalCorners();
  1163. }
  1164. }
  1165. /// <summary>
  1166. ///
  1167. /// </summary>
  1168. protected override void OnDidApplyAnimationProperties()
  1169. {
  1170. m_havePropertiesChanged = true;
  1171. SetVerticesDirty();
  1172. SetLayoutDirty();
  1173. //Debug.Log("Animation Properties have changed.");
  1174. }
  1175. protected override void OnCanvasHierarchyChanged()
  1176. {
  1177. base.OnCanvasHierarchyChanged();
  1178. m_canvas = canvas;
  1179. if (!m_isAwake || !isActiveAndEnabled)
  1180. return;
  1181. // Special handling to stop InternalUpdate calls when parent Canvas is disabled.
  1182. if (m_canvas == null || m_canvas.enabled == false)
  1183. TMP_UpdateManager.UnRegisterTextObjectForUpdate(this);
  1184. else if (m_IsTextObjectScaleStatic == false)
  1185. TMP_UpdateManager.RegisterTextObjectForUpdate(this);
  1186. }
  1187. protected override void OnTransformParentChanged()
  1188. {
  1189. //Debug.Log("***** OnTransformParentChanged *****");
  1190. base.OnTransformParentChanged();
  1191. m_canvas = this.canvas;
  1192. ComputeMarginSize();
  1193. m_havePropertiesChanged = true;
  1194. }
  1195. protected override void OnRectTransformDimensionsChange()
  1196. {
  1197. //Debug.Log("*** OnRectTransformDimensionsChange() *** ActiveInHierarchy: " + this.gameObject.activeInHierarchy + " Frame: " + Time.frameCount);
  1198. // Make sure object is active in Hierarchy
  1199. if (!this.gameObject.activeInHierarchy)
  1200. return;
  1201. // Ignore changes to RectTransform SizeDelta that are very small and typically the result of rounding errors when using RectTransform in Anchor Stretch mode.
  1202. if (rectTransform != null &&
  1203. Mathf.Abs(m_rectTransform.rect.width - m_PreviousRectTransformSize.x) < 0.0001f && Mathf.Abs(m_rectTransform.rect.height - m_PreviousRectTransformSize.y) < 0.0001f &&
  1204. Mathf.Abs(m_rectTransform.pivot.x - m_PreviousPivotPosition.x) < 0.0001f && Mathf.Abs(m_rectTransform.pivot.y - m_PreviousPivotPosition.y) < 0.0001f)
  1205. {
  1206. return;
  1207. }
  1208. ComputeMarginSize();
  1209. UpdateSubObjectPivot();
  1210. SetVerticesDirty();
  1211. SetLayoutDirty();
  1212. }
  1213. /// <summary>
  1214. /// Function used as a replacement for LateUpdate to check if the transform or scale of the text object has changed.
  1215. /// </summary>
  1216. internal override void InternalUpdate()
  1217. {
  1218. // We need to update the SDF scale or possibly regenerate the text object if lossy scale has changed.
  1219. if (m_havePropertiesChanged == false)
  1220. {
  1221. float lossyScaleY = m_rectTransform.lossyScale.y;
  1222. // Ignore very small lossy scale changes as their effect on SDF Scale would not be visually noticeable.
  1223. // Do not update SDF Scale if the text is null or empty
  1224. if (Mathf.Abs(lossyScaleY - m_previousLossyScaleY) > 0.0001f && m_InternalParsingBuffer[0].unicode != 0)
  1225. {
  1226. float scaleDelta = lossyScaleY / m_previousLossyScaleY;
  1227. UpdateSDFScale(scaleDelta);
  1228. m_previousLossyScaleY = lossyScaleY;
  1229. }
  1230. }
  1231. // Added to handle legacy animation mode.
  1232. if (m_isUsingLegacyAnimationComponent)
  1233. {
  1234. //if (m_havePropertiesChanged)
  1235. m_havePropertiesChanged = true;
  1236. OnPreRenderCanvas();
  1237. }
  1238. }
  1239. // Called just before the Canvas is rendered.
  1240. void OnPreRenderCanvas()
  1241. {
  1242. //Debug.Log("*** OnPreRenderCanvas() *** Frame: " + Time.frameCount);
  1243. // Make sure object is active and that we have a valid Canvas.
  1244. if (!m_isAwake || (this.IsActive() == false && m_ignoreActiveState == false))
  1245. return;
  1246. if (m_canvas == null) { m_canvas = this.canvas; if (m_canvas == null) return; }
  1247. // Check if we have a font asset assigned. Return if we don't because no one likes to see purple squares on screen.
  1248. if (m_fontAsset == null)
  1249. {
  1250. Debug.LogWarning("Please assign a Font Asset to this " + transform.name + " gameobject.", this);
  1251. return;
  1252. }
  1253. if (m_havePropertiesChanged || m_isLayoutDirty)
  1254. {
  1255. //Debug.Log("Properties have changed!"); // Assigned Material is:" + m_sharedMaterial); // New Text is: " + m_text + ".");
  1256. // Update mesh padding if necessary.
  1257. if (checkPaddingRequired)
  1258. UpdateMeshPadding();
  1259. // Reparse the text if the input has changed or text was truncated.
  1260. if (m_isInputParsingRequired || m_isTextTruncated)
  1261. {
  1262. #if TMP_PROFILE_ON
  1263. Profiler.BeginSample("TMP - ParseInputText()");
  1264. #endif
  1265. ParseInputText();
  1266. TMP_FontAsset.UpdateFontFeaturesForFontAssetsInQueue();
  1267. #if TMP_PROFILE_ON
  1268. Profiler.EndSample();
  1269. #endif
  1270. }
  1271. // Reset Font min / max used with Auto-sizing
  1272. if (m_enableAutoSizing)
  1273. m_fontSize = Mathf.Clamp(m_fontSizeBase, m_fontSizeMin, m_fontSizeMax);
  1274. m_maxFontSize = m_fontSizeMax;
  1275. m_minFontSize = m_fontSizeMin;
  1276. m_lineSpacingDelta = 0;
  1277. m_charWidthAdjDelta = 0;
  1278. m_isTextTruncated = false;
  1279. m_havePropertiesChanged = false;
  1280. m_isLayoutDirty = false;
  1281. m_ignoreActiveState = false;
  1282. // Reset Text Auto Size iteration tracking.
  1283. m_IsAutoSizePointSizeSet = false;
  1284. m_AutoSizeIterationCount = 0;
  1285. // The GenerateTextMesh function is potentially called repeatedly when text auto size is enabled.
  1286. // This is a revised implementation to remove the use of recursion which could potentially result in stack overflow issues.
  1287. while (m_IsAutoSizePointSizeSet == false)
  1288. {
  1289. GenerateTextMesh();
  1290. m_AutoSizeIterationCount += 1;
  1291. }
  1292. }
  1293. }
  1294. /// <summary>
  1295. /// This is the main function that is responsible for creating / displaying the text.
  1296. /// </summary>
  1297. protected override void GenerateTextMesh()
  1298. {
  1299. #if TMP_PROFILE_ON
  1300. Profiler.BeginSample("TMP GenerateText()");
  1301. //Debug.Log("***** GenerateTextMesh() called on object ID " + GetInstanceID() + ". *****"); // ***** Frame: " + Time.frameCount); // + ". Point Size: " + m_fontSize + ". Margins are (W) " + m_marginWidth + " (H) " + m_marginHeight); // ". Iteration Count: " + loopCountA + ". Min: " + m_minFontSize + " Max: " + m_maxFontSize + " Delta: " + (m_maxFontSize - m_minFontSize) + " Font size is " + m_fontSize); //called for Object with ID " + GetInstanceID()); // Assigned Material is " + m_uiRenderer.GetMaterial().name); // IncludeForMasking " + this.m_IncludeForMasking); // and text is " + m_text);
  1302. #endif
  1303. // Early exit if no font asset was assigned. This should not be needed since LiberationSans SDF will be assigned by default.
  1304. if (m_fontAsset == null || m_fontAsset.characterLookupTable == null)
  1305. {
  1306. Debug.LogWarning("Can't Generate Mesh! No Font Asset has been assigned to Object ID: " + this.GetInstanceID());
  1307. m_IsAutoSizePointSizeSet = true;
  1308. return;
  1309. }
  1310. // Clear TextInfo
  1311. if (m_textInfo != null)
  1312. m_textInfo.Clear();
  1313. // Early exit if we don't have any Text to generate.
  1314. if (m_InternalParsingBuffer == null || m_InternalParsingBuffer.Length == 0 || m_InternalParsingBuffer[0].unicode == 0)
  1315. {
  1316. // Clear mesh and upload changes to the mesh.
  1317. ClearMesh();
  1318. m_preferredWidth = 0;
  1319. m_preferredHeight = 0;
  1320. // Event indicating the text has been regenerated.
  1321. TMPro_EventManager.ON_TEXT_CHANGED(this);
  1322. m_IsAutoSizePointSizeSet = true;
  1323. return;
  1324. }
  1325. m_currentFontAsset = m_fontAsset;
  1326. m_currentMaterial = m_sharedMaterial;
  1327. m_currentMaterialIndex = 0;
  1328. m_materialReferenceStack.SetDefault(new MaterialReference(m_currentMaterialIndex, m_currentFontAsset, null, m_currentMaterial, m_padding));
  1329. m_currentSpriteAsset = m_spriteAsset;
  1330. // Stop all Sprite Animations
  1331. if (m_spriteAnimator != null)
  1332. m_spriteAnimator.StopAllAnimations();
  1333. // Total character count is computed when the text is parsed.
  1334. int totalCharacterCount = m_totalCharacterCount;
  1335. // Calculate the scale of the font based on selected font size and sampling point size.
  1336. // baseScale is calculated using the font asset assigned to the text object.
  1337. float baseScale = m_fontScale = (m_fontSize / m_fontAsset.m_FaceInfo.pointSize * m_fontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f));
  1338. float currentElementScale = baseScale;
  1339. float currentEmScale = m_fontSize * 0.01f * (m_isOrthographic ? 1 : 0.1f);
  1340. m_fontScaleMultiplier = 1;
  1341. m_currentFontSize = m_fontSize;
  1342. m_sizeStack.SetDefault(m_currentFontSize);
  1343. float fontSizeDelta = 0;
  1344. int charCode = 0; // Holds the character code of the currently being processed character.
  1345. m_FontStyleInternal = m_fontStyle; // Set the default style.
  1346. m_FontWeightInternal = (m_FontStyleInternal & FontStyles.Bold) == FontStyles.Bold ? FontWeight.Bold : m_fontWeight;
  1347. m_FontWeightStack.SetDefault(m_FontWeightInternal);
  1348. m_fontStyleStack.Clear();
  1349. m_lineJustification = m_HorizontalAlignment; // m_textAlignment; // Sets the line justification mode to match editor alignment.
  1350. m_lineJustificationStack.SetDefault(m_lineJustification);
  1351. float padding = 0;
  1352. float style_padding = 0; // Extra padding required to accommodate Bold style.
  1353. float boldSpacingAdjustment = 0;
  1354. //float bold_xAdvance_multiplier = 1; // Used to increase spacing between character when style is bold.
  1355. m_baselineOffset = 0; // Used by subscript characters.
  1356. m_baselineOffsetStack.Clear();
  1357. // Underline
  1358. bool beginUnderline = false;
  1359. Vector3 underline_start = Vector3.zero; // Used to track where underline starts & ends.
  1360. Vector3 underline_end = Vector3.zero;
  1361. // Strike-through
  1362. bool beginStrikethrough = false;
  1363. Vector3 strikethrough_start = Vector3.zero;
  1364. Vector3 strikethrough_end = Vector3.zero;
  1365. // Text Highlight
  1366. bool beginHighlight = false;
  1367. Vector3 highlight_start = Vector3.zero;
  1368. Vector3 highlight_end = Vector3.zero;
  1369. m_fontColor32 = m_fontColor;
  1370. Color32 vertexColor;
  1371. m_htmlColor = m_fontColor32;
  1372. m_underlineColor = m_htmlColor;
  1373. m_strikethroughColor = m_htmlColor;
  1374. m_colorStack.SetDefault(m_htmlColor);
  1375. m_underlineColorStack.SetDefault(m_htmlColor);
  1376. m_strikethroughColorStack.SetDefault(m_htmlColor);
  1377. m_HighlightStateStack.SetDefault(new HighlightState(m_htmlColor, TMP_Offset.zero));
  1378. m_colorGradientPreset = null;
  1379. m_colorGradientStack.SetDefault(null);
  1380. m_ItalicAngle = m_currentFontAsset.italicStyle;
  1381. m_ItalicAngleStack.SetDefault(m_ItalicAngle);
  1382. // Clear the Style stack.
  1383. //m_styleStack.Clear();
  1384. // Clear the Action stack.
  1385. m_actionStack.Clear();
  1386. m_isFXMatrixSet = false;
  1387. m_lineOffset = 0; // Amount of space between lines (font line spacing + m_linespacing).
  1388. m_lineHeight = TMP_Math.FLOAT_UNSET;
  1389. float lineGap = m_currentFontAsset.m_FaceInfo.lineHeight - (m_currentFontAsset.m_FaceInfo.ascentLine - m_currentFontAsset.m_FaceInfo.descentLine);
  1390. m_cSpacing = 0; // Amount of space added between characters as a result of the use of the <cspace> tag.
  1391. m_monoSpacing = 0;
  1392. m_xAdvance = 0; // Used to track the position of each character.
  1393. tag_LineIndent = 0; // Used for indentation of text.
  1394. tag_Indent = 0;
  1395. m_indentStack.SetDefault(0);
  1396. tag_NoParsing = false;
  1397. //m_isIgnoringAlignment = false;
  1398. m_characterCount = 0; // Total characters in the char[]
  1399. // Tracking of line information
  1400. m_firstCharacterOfLine = m_firstVisibleCharacter;
  1401. m_lastCharacterOfLine = 0;
  1402. m_firstVisibleCharacterOfLine = 0;
  1403. m_lastVisibleCharacterOfLine = 0;
  1404. m_maxLineAscender = k_LargeNegativeFloat;
  1405. m_maxLineDescender = k_LargePositiveFloat;
  1406. m_lineNumber = 0;
  1407. m_startOfLineAscender = 0;
  1408. m_startOfLineDescender = 0;
  1409. m_lineVisibleCharacterCount = 0;
  1410. bool isStartOfNewLine = true;
  1411. m_IsDrivenLineSpacing = false;
  1412. m_firstOverflowCharacterIndex = -1;
  1413. m_pageNumber = 0;
  1414. int pageToDisplay = Mathf.Clamp(m_pageToDisplay - 1, 0, m_textInfo.pageInfo.Length - 1);
  1415. m_textInfo.ClearPageInfo();
  1416. Vector4 margins = m_margin;
  1417. float marginWidth = m_marginWidth > 0 ? m_marginWidth : 0;
  1418. float marginHeight = m_marginHeight > 0 ? m_marginHeight : 0;
  1419. m_marginLeft = 0;
  1420. m_marginRight = 0;
  1421. m_width = -1;
  1422. float widthOfTextArea = marginWidth + 0.0001f - m_marginLeft - m_marginRight;
  1423. // Need to initialize these Extents structures
  1424. m_meshExtents.min = k_LargePositiveVector2;
  1425. m_meshExtents.max = k_LargeNegativeVector2;
  1426. // Initialize lineInfo
  1427. m_textInfo.ClearLineInfo();
  1428. // Tracking of the highest Ascender
  1429. m_maxCapHeight = 0;
  1430. m_maxTextAscender = 0;
  1431. m_ElementDescender = 0;
  1432. m_PageAscender = 0;
  1433. float maxVisibleDescender = 0;
  1434. bool isMaxVisibleDescenderSet = false;
  1435. m_isNewPage = false;
  1436. // Initialize struct to track states of word wrapping
  1437. bool isFirstWordOfLine = true;
  1438. m_isNonBreakingSpace = false;
  1439. bool ignoreNonBreakingSpace = false;
  1440. //bool isLastCharacterCJK = false;
  1441. int lastSoftLineBreak = 0;
  1442. CharacterSubstitution characterToSubstitute = new CharacterSubstitution(-1, 0);
  1443. bool isSoftHyphenIgnored = false;
  1444. bool isInjectingCharacter = false;
  1445. // Save character and line state before we begin layout.
  1446. SaveWordWrappingState(ref m_SavedWordWrapState, -1, -1);
  1447. SaveWordWrappingState(ref m_SavedLineState, -1, -1);
  1448. SaveWordWrappingState(ref m_SavedEllipsisState, -1, -1);
  1449. SaveWordWrappingState(ref m_SavedLastValidState, -1, -1);
  1450. SaveWordWrappingState(ref m_SavedSoftLineBreakState, -1, -1);
  1451. m_EllipsisInsertionCandidateStack.Clear();
  1452. // Safety Tracker
  1453. int restoreCount = 0;
  1454. #if TMP_PROFILE_ON
  1455. Profiler.BeginSample("TMP GenerateText() - Phase I");
  1456. #endif
  1457. // Parse through Character buffer to read HTML tags and begin creating mesh.
  1458. for (int i = 0; i < m_InternalParsingBuffer.Length && m_InternalParsingBuffer[i].unicode != 0; i++)
  1459. {
  1460. charCode = m_InternalParsingBuffer[i].unicode;
  1461. if (restoreCount > 5)
  1462. {
  1463. Debug.LogError("Line breaking recursion max threshold hit... Character [" + charCode + "] index: " + i);
  1464. characterToSubstitute.index = m_characterCount;
  1465. characterToSubstitute.unicode = 0x03;
  1466. }
  1467. // Parse Rich Text Tag
  1468. #region Parse Rich Text Tag
  1469. if (m_isRichText && charCode == 60) // '<'
  1470. {
  1471. #if TMP_PROFILE_ON
  1472. Profiler.BeginSample("TMP - Parse Rich Text Tags");
  1473. #endif
  1474. m_isParsingText = true;
  1475. m_textElementType = TMP_TextElementType.Character;
  1476. int endTagIndex;
  1477. // Check if Tag is valid. If valid, skip to the end of the validated tag.
  1478. if (ValidateHtmlTag(m_InternalParsingBuffer, i + 1, out endTagIndex))
  1479. {
  1480. i = endTagIndex;
  1481. // Continue to next character or handle the sprite element
  1482. if (m_textElementType == TMP_TextElementType.Character)
  1483. {
  1484. #if TMP_PROFILE_ON
  1485. Profiler.EndSample();
  1486. #endif
  1487. continue;
  1488. }
  1489. }
  1490. #if TMP_PROFILE_ON
  1491. Profiler.EndSample();
  1492. #endif
  1493. }
  1494. else
  1495. {
  1496. m_textElementType = m_textInfo.characterInfo[m_characterCount].elementType;
  1497. m_currentMaterialIndex = m_textInfo.characterInfo[m_characterCount].materialReferenceIndex;
  1498. m_currentFontAsset = m_textInfo.characterInfo[m_characterCount].fontAsset;
  1499. }
  1500. #endregion End Parse Rich Text Tag
  1501. int previousMaterialIndex = m_currentMaterialIndex;
  1502. bool isUsingAltTypeface = m_textInfo.characterInfo[m_characterCount].isUsingAlternateTypeface;
  1503. m_isParsingText = false;
  1504. // Handle potential character substitutions
  1505. #region Character Substitutions
  1506. isInjectingCharacter = false;
  1507. if (characterToSubstitute.index == m_characterCount)
  1508. {
  1509. charCode = (int)characterToSubstitute.unicode;
  1510. m_textElementType = TMP_TextElementType.Character;
  1511. isInjectingCharacter = true;
  1512. switch (charCode)
  1513. {
  1514. case 0x03:
  1515. m_textInfo.characterInfo[m_characterCount].textElement = m_currentFontAsset.characterLookupTable[0x03];
  1516. m_isTextTruncated = true;
  1517. break;
  1518. case 0x2D:
  1519. //
  1520. break;
  1521. case 0x2026:
  1522. m_textInfo.characterInfo[m_characterCount].textElement = m_Ellipsis.character;
  1523. m_textInfo.characterInfo[m_characterCount].elementType = TMP_TextElementType.Character;
  1524. m_textInfo.characterInfo[m_characterCount].fontAsset = m_Ellipsis.fontAsset;
  1525. m_textInfo.characterInfo[m_characterCount].material = m_Ellipsis.material;
  1526. m_textInfo.characterInfo[m_characterCount].materialReferenceIndex = m_Ellipsis.materialIndex;
  1527. // Indicates the source parsing data has been modified.
  1528. m_isTextTruncated = true;
  1529. // End Of Text
  1530. characterToSubstitute.index = m_characterCount + 1;
  1531. characterToSubstitute.unicode = 0x03;
  1532. break;
  1533. }
  1534. }
  1535. #endregion
  1536. // When using Linked text, mark character as ignored and skip to next character.
  1537. #region Linked Text
  1538. if (m_characterCount < m_firstVisibleCharacter && charCode != 0x03)
  1539. {
  1540. m_textInfo.characterInfo[m_characterCount].isVisible = false;
  1541. m_textInfo.characterInfo[m_characterCount].character = (char)0x200B;
  1542. m_textInfo.characterInfo[m_characterCount].lineNumber = 0;
  1543. m_characterCount += 1;
  1544. continue;
  1545. }
  1546. #endregion
  1547. // Handle Font Styles like LowerCase, UpperCase and SmallCaps.
  1548. #region Handling of LowerCase, UpperCase and SmallCaps Font Styles
  1549. float smallCapsMultiplier = 1.0f;
  1550. if (m_textElementType == TMP_TextElementType.Character)
  1551. {
  1552. if ((m_FontStyleInternal & FontStyles.UpperCase) == FontStyles.UpperCase)
  1553. {
  1554. // If this character is lowercase, switch to uppercase.
  1555. if (char.IsLower((char)charCode))
  1556. charCode = char.ToUpper((char)charCode);
  1557. }
  1558. else if ((m_FontStyleInternal & FontStyles.LowerCase) == FontStyles.LowerCase)
  1559. {
  1560. // If this character is uppercase, switch to lowercase.
  1561. if (char.IsUpper((char)charCode))
  1562. charCode = char.ToLower((char)charCode);
  1563. }
  1564. else if ((m_FontStyleInternal & FontStyles.SmallCaps) == FontStyles.SmallCaps)
  1565. {
  1566. if (char.IsLower((char)charCode))
  1567. {
  1568. smallCapsMultiplier = 0.8f;
  1569. charCode = char.ToUpper((char)charCode);
  1570. }
  1571. }
  1572. }
  1573. #endregion
  1574. // Look up Character Data from Dictionary and cache it.
  1575. #region Look up Character Data
  1576. #if TMP_PROFILE_ON
  1577. Profiler.BeginSample("TMP - Lookup Character & Glyph Data");
  1578. #endif
  1579. float baselineOffset = 0;
  1580. float elementAscentLine = 0;
  1581. float elementDescentLine = 0;
  1582. if (m_textElementType == TMP_TextElementType.Sprite)
  1583. {
  1584. // If a sprite is used as a fallback then get a reference to it and set the color to white.
  1585. m_currentSpriteAsset = m_textInfo.characterInfo[m_characterCount].spriteAsset;
  1586. m_spriteIndex = m_textInfo.characterInfo[m_characterCount].spriteIndex;
  1587. TMP_SpriteCharacter sprite = m_currentSpriteAsset.spriteCharacterTable[m_spriteIndex];
  1588. if (sprite == null) continue;
  1589. // Sprites are assigned in the E000 Private Area + sprite Index
  1590. if (charCode == 60)
  1591. charCode = 57344 + m_spriteIndex;
  1592. else
  1593. m_spriteColor = s_colorWhite;
  1594. // The sprite scale calculations are based on the font asset assigned to the text object.
  1595. if (m_currentSpriteAsset.m_FaceInfo.pointSize > 0)
  1596. {
  1597. float spriteScale = m_currentFontSize / m_currentSpriteAsset.m_FaceInfo.pointSize * m_currentSpriteAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f);
  1598. currentElementScale = sprite.m_Scale * sprite.m_Glyph.scale * spriteScale;
  1599. elementAscentLine = m_currentSpriteAsset.m_FaceInfo.ascentLine;
  1600. baselineOffset = m_currentSpriteAsset.m_FaceInfo.baseline * m_fontScale * m_fontScaleMultiplier * m_currentSpriteAsset.m_FaceInfo.scale;
  1601. elementDescentLine = m_currentSpriteAsset.m_FaceInfo.descentLine;
  1602. }
  1603. else
  1604. {
  1605. float spriteScale = m_currentFontSize / m_currentFontAsset.m_FaceInfo.pointSize * m_currentFontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f);
  1606. currentElementScale = m_currentFontAsset.m_FaceInfo.ascentLine / sprite.m_Glyph.metrics.height * sprite.m_Scale * sprite.m_Glyph.scale * spriteScale;
  1607. float scaleDelta = spriteScale / currentElementScale;
  1608. elementAscentLine = m_currentFontAsset.m_FaceInfo.ascentLine * scaleDelta;
  1609. baselineOffset = m_currentFontAsset.m_FaceInfo.baseline * m_fontScale * m_fontScaleMultiplier * m_currentFontAsset.m_FaceInfo.scale;
  1610. elementDescentLine = m_currentFontAsset.m_FaceInfo.descentLine * scaleDelta;
  1611. }
  1612. m_cached_TextElement = sprite;
  1613. m_textInfo.characterInfo[m_characterCount].elementType = TMP_TextElementType.Sprite;
  1614. m_textInfo.characterInfo[m_characterCount].scale = currentElementScale;
  1615. m_textInfo.characterInfo[m_characterCount].spriteAsset = m_currentSpriteAsset;
  1616. m_textInfo.characterInfo[m_characterCount].fontAsset = m_currentFontAsset;
  1617. m_textInfo.characterInfo[m_characterCount].materialReferenceIndex = m_currentMaterialIndex;
  1618. m_currentMaterialIndex = previousMaterialIndex;
  1619. padding = 0;
  1620. }
  1621. else if (m_textElementType == TMP_TextElementType.Character)
  1622. {
  1623. m_cached_TextElement = m_textInfo.characterInfo[m_characterCount].textElement;
  1624. if (m_cached_TextElement == null) continue;
  1625. m_currentFontAsset = m_textInfo.characterInfo[m_characterCount].fontAsset;
  1626. m_currentMaterial = m_textInfo.characterInfo[m_characterCount].material;
  1627. m_currentMaterialIndex = m_textInfo.characterInfo[m_characterCount].materialReferenceIndex;
  1628. // Special handling if replaced character was a line feed where in this case we have to use the scale of the previous character.
  1629. float adjustedScale;
  1630. if (isInjectingCharacter && m_InternalParsingBuffer[i].unicode == 0x0A && m_characterCount != m_firstCharacterOfLine)
  1631. adjustedScale = m_textInfo.characterInfo[m_characterCount - 1].pointSize * smallCapsMultiplier / m_currentFontAsset.m_FaceInfo.pointSize * m_currentFontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f);
  1632. else
  1633. adjustedScale = m_currentFontSize * smallCapsMultiplier / m_currentFontAsset.m_FaceInfo.pointSize * m_currentFontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f);
  1634. elementAscentLine = m_currentFontAsset.m_FaceInfo.ascentLine;
  1635. elementDescentLine = m_currentFontAsset.m_FaceInfo.descentLine;
  1636. currentElementScale = adjustedScale * m_fontScaleMultiplier * m_cached_TextElement.m_Scale * m_cached_TextElement.m_Glyph.scale;
  1637. baselineOffset = m_currentFontAsset.m_FaceInfo.baseline * adjustedScale * m_fontScaleMultiplier * m_currentFontAsset.m_FaceInfo.scale;
  1638. m_textInfo.characterInfo[m_characterCount].elementType = TMP_TextElementType.Character;
  1639. m_textInfo.characterInfo[m_characterCount].scale = currentElementScale;
  1640. padding = m_currentMaterialIndex == 0 ? m_padding : m_subTextObjects[m_currentMaterialIndex].padding;
  1641. }
  1642. #if TMP_PROFILE_ON
  1643. Profiler.EndSample();
  1644. #endif
  1645. #endregion
  1646. // Handle Soft Hyphen
  1647. #region Handle Soft Hyphen
  1648. float currentElementUnmodifiedScale = currentElementScale;
  1649. if (charCode == 0xAD || charCode == 0x03)
  1650. currentElementScale = 0;
  1651. #endregion
  1652. // Store some of the text object's information
  1653. m_textInfo.characterInfo[m_characterCount].character = (char)charCode;
  1654. m_textInfo.characterInfo[m_characterCount].pointSize = m_currentFontSize;
  1655. m_textInfo.characterInfo[m_characterCount].color = m_htmlColor;
  1656. m_textInfo.characterInfo[m_characterCount].underlineColor = m_underlineColor;
  1657. m_textInfo.characterInfo[m_characterCount].strikethroughColor = m_strikethroughColor;
  1658. m_textInfo.characterInfo[m_characterCount].highlightState = m_HighlightStateStack.current;
  1659. m_textInfo.characterInfo[m_characterCount].style = m_FontStyleInternal;
  1660. // Cache glyph metrics
  1661. GlyphMetrics currentGlyphMetrics = m_cached_TextElement.m_Glyph.metrics;
  1662. // Optimization to avoid calling this more than once per character.
  1663. bool isWhiteSpace = char.IsWhiteSpace((char)charCode);
  1664. //bool isVisibleCharacter = !isWhiteSpace;
  1665. // Handle Kerning if Enabled.
  1666. #region Handle Kerning
  1667. TMP_GlyphValueRecord glyphAdjustments = new TMP_GlyphValueRecord();
  1668. float characterSpacingAdjustment = m_characterSpacing;
  1669. m_GlyphHorizontalAdvanceAdjustment = 0;
  1670. if (m_enableKerning)
  1671. {
  1672. #if TMP_PROFILE_ON
  1673. Profiler.BeginSample("TMP - Handle Glyph Positional Adjustments");
  1674. #endif
  1675. TMP_GlyphPairAdjustmentRecord adjustmentPair;
  1676. uint baseGlyphIndex = m_cached_TextElement.m_GlyphIndex;
  1677. if (m_characterCount < totalCharacterCount - 1)
  1678. {
  1679. uint nextGlyphIndex = m_textInfo.characterInfo[m_characterCount + 1].textElement.m_GlyphIndex;
  1680. uint key = nextGlyphIndex << 16 | baseGlyphIndex;
  1681. if (m_currentFontAsset.m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.TryGetValue(key, out adjustmentPair))
  1682. {
  1683. glyphAdjustments = adjustmentPair.m_FirstAdjustmentRecord.m_GlyphValueRecord;
  1684. characterSpacingAdjustment = (adjustmentPair.m_FeatureLookupFlags & FontFeatureLookupFlags.IgnoreSpacingAdjustments) == FontFeatureLookupFlags.IgnoreSpacingAdjustments ? 0 : characterSpacingAdjustment;
  1685. }
  1686. }
  1687. if (m_characterCount >= 1)
  1688. {
  1689. uint previousGlyphIndex = m_textInfo.characterInfo[m_characterCount - 1].textElement.m_GlyphIndex;
  1690. uint key = baseGlyphIndex << 16 | previousGlyphIndex;
  1691. if (m_currentFontAsset.m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.TryGetValue(key, out adjustmentPair))
  1692. {
  1693. glyphAdjustments += adjustmentPair.m_SecondAdjustmentRecord.m_GlyphValueRecord;
  1694. characterSpacingAdjustment = (adjustmentPair.m_FeatureLookupFlags & FontFeatureLookupFlags.IgnoreSpacingAdjustments) == FontFeatureLookupFlags.IgnoreSpacingAdjustments ? 0 : characterSpacingAdjustment;
  1695. }
  1696. }
  1697. m_GlyphHorizontalAdvanceAdjustment = glyphAdjustments.xAdvance;
  1698. #if TMP_PROFILE_ON
  1699. Profiler.EndSample();
  1700. #endif
  1701. }
  1702. #endregion
  1703. // Initial Implementation for RTL support.
  1704. #region Handle Right-to-Left
  1705. if (m_isRightToLeft)
  1706. {
  1707. m_xAdvance -= currentGlyphMetrics.horizontalAdvance * (1 - m_charWidthAdjDelta) * currentElementScale;
  1708. if (isWhiteSpace || charCode == 0x200B)
  1709. m_xAdvance -= m_wordSpacing * currentEmScale;
  1710. }
  1711. #endregion
  1712. // Handle Mono Spacing
  1713. #region Handle Mono Spacing
  1714. float monoAdvance = 0;
  1715. if (m_monoSpacing != 0)
  1716. {
  1717. monoAdvance = (m_monoSpacing / 2 - (currentGlyphMetrics.width / 2 + currentGlyphMetrics.horizontalBearingX) * currentElementScale) * (1 - m_charWidthAdjDelta);
  1718. m_xAdvance += monoAdvance;
  1719. }
  1720. #endregion
  1721. // Set Padding based on selected font style
  1722. #region Handle Style Padding
  1723. if (m_textElementType == TMP_TextElementType.Character && !isUsingAltTypeface && ((m_FontStyleInternal & FontStyles.Bold) == FontStyles.Bold)) // Checks for any combination of Bold Style.
  1724. {
  1725. if (m_currentMaterial != null && m_currentMaterial.HasProperty(ShaderUtilities.ID_GradientScale))
  1726. {
  1727. float gradientScale = m_currentMaterial.GetFloat(ShaderUtilities.ID_GradientScale);
  1728. style_padding = m_currentFontAsset.boldStyle / 4.0f * gradientScale * m_currentMaterial.GetFloat(ShaderUtilities.ID_ScaleRatio_A);
  1729. // Clamp overall padding to Gradient Scale size.
  1730. if (style_padding + padding > gradientScale)
  1731. padding = gradientScale - style_padding;
  1732. }
  1733. else
  1734. style_padding = 0;
  1735. boldSpacingAdjustment = m_currentFontAsset.boldSpacing;
  1736. }
  1737. else
  1738. {
  1739. if (m_currentMaterial != null && m_currentMaterial.HasProperty(ShaderUtilities.ID_GradientScale))
  1740. {
  1741. float gradientScale = m_currentMaterial.GetFloat(ShaderUtilities.ID_GradientScale);
  1742. style_padding = m_currentFontAsset.normalStyle / 4.0f * gradientScale * m_currentMaterial.GetFloat(ShaderUtilities.ID_ScaleRatio_A);
  1743. // Clamp overall padding to Gradient Scale size.
  1744. if (style_padding + padding > gradientScale)
  1745. padding = gradientScale - style_padding;
  1746. }
  1747. else
  1748. style_padding = 0;
  1749. boldSpacingAdjustment = 0;
  1750. }
  1751. #endregion Handle Style Padding
  1752. // Determine the position of the vertices of the Character or Sprite.
  1753. #region Calculate Vertices Position
  1754. #if TMP_PROFILE_ON
  1755. Profiler.BeginSample("TMP - Calculate Vertices Position");
  1756. #endif
  1757. Vector3 top_left;
  1758. top_left.x = m_xAdvance + ((currentGlyphMetrics.horizontalBearingX - padding - style_padding + glyphAdjustments.m_XPlacement) * currentElementScale * (1 - m_charWidthAdjDelta));
  1759. top_left.y = baselineOffset + (currentGlyphMetrics.horizontalBearingY + padding + glyphAdjustments.m_YPlacement) * currentElementScale - m_lineOffset + m_baselineOffset;
  1760. top_left.z = 0;
  1761. Vector3 bottom_left;
  1762. bottom_left.x = top_left.x;
  1763. bottom_left.y = top_left.y - ((currentGlyphMetrics.height + padding * 2) * currentElementScale);
  1764. bottom_left.z = 0;
  1765. Vector3 top_right;
  1766. top_right.x = bottom_left.x + ((currentGlyphMetrics.width + padding * 2 + style_padding * 2) * currentElementScale * (1 - m_charWidthAdjDelta));
  1767. top_right.y = top_left.y;
  1768. top_right.z = 0;
  1769. Vector3 bottom_right;
  1770. bottom_right.x = top_right.x;
  1771. bottom_right.y = bottom_left.y;
  1772. bottom_right.z = 0;
  1773. #if TMP_PROFILE_ON
  1774. Profiler.EndSample();
  1775. #endif
  1776. #endregion
  1777. // Check if we need to Shear the rectangles for Italic styles
  1778. #region Handle Italic & Shearing
  1779. if (m_textElementType == TMP_TextElementType.Character && !isUsingAltTypeface && ((m_FontStyleInternal & FontStyles.Italic) == FontStyles.Italic))
  1780. {
  1781. // Shift Top vertices forward by half (Shear Value * height of character) and Bottom vertices back by same amount.
  1782. float shear_value = m_ItalicAngle * 0.01f;
  1783. Vector3 topShear = new Vector3(shear_value * ((currentGlyphMetrics.horizontalBearingY + padding + style_padding) * currentElementScale), 0, 0);
  1784. Vector3 bottomShear = new Vector3(shear_value * (((currentGlyphMetrics.horizontalBearingY - currentGlyphMetrics.height - padding - style_padding)) * currentElementScale), 0, 0);
  1785. Vector3 shearAdjustment = new Vector3((topShear.x - bottomShear.x) / 2, 0, 0);
  1786. top_left = top_left + topShear - shearAdjustment;
  1787. bottom_left = bottom_left + bottomShear - shearAdjustment;
  1788. top_right = top_right + topShear - shearAdjustment;
  1789. bottom_right = bottom_right + bottomShear - shearAdjustment;
  1790. }
  1791. #endregion Handle Italics & Shearing
  1792. // Handle Character Rotation
  1793. #region Handle Character Rotation
  1794. if (m_isFXMatrixSet)
  1795. {
  1796. // Apply scale matrix when simulating Condensed text.
  1797. if (m_FXMatrix.lossyScale.x != 1)
  1798. {
  1799. //top_left = m_FXMatrix.MultiplyPoint3x4(top_left);
  1800. //bottom_left = m_FXMatrix.MultiplyPoint3x4(bottom_left);
  1801. //top_right = m_FXMatrix.MultiplyPoint3x4(top_right);
  1802. //bottom_right = m_FXMatrix.MultiplyPoint3x4(bottom_right);
  1803. }
  1804. Vector3 positionOffset = (top_right + bottom_left) / 2;
  1805. top_left = m_FXMatrix.MultiplyPoint3x4(top_left - positionOffset) + positionOffset;
  1806. bottom_left = m_FXMatrix.MultiplyPoint3x4(bottom_left - positionOffset) + positionOffset;
  1807. top_right = m_FXMatrix.MultiplyPoint3x4(top_right - positionOffset) + positionOffset;
  1808. bottom_right = m_FXMatrix.MultiplyPoint3x4(bottom_right - positionOffset) + positionOffset;
  1809. }
  1810. #endregion
  1811. // Store vertex information for the character or sprite.
  1812. m_textInfo.characterInfo[m_characterCount].bottomLeft = bottom_left;
  1813. m_textInfo.characterInfo[m_characterCount].topLeft = top_left;
  1814. m_textInfo.characterInfo[m_characterCount].topRight = top_right;
  1815. m_textInfo.characterInfo[m_characterCount].bottomRight = bottom_right;
  1816. m_textInfo.characterInfo[m_characterCount].origin = m_xAdvance;
  1817. m_textInfo.characterInfo[m_characterCount].baseLine = baselineOffset - m_lineOffset + m_baselineOffset;
  1818. m_textInfo.characterInfo[m_characterCount].aspectRatio = (top_right.x - bottom_left.x) / (top_left.y - bottom_left.y);
  1819. // Compute text metrics
  1820. #region Compute Ascender & Descender values
  1821. #if TMP_PROFILE_ON
  1822. Profiler.BeginSample("TMP - Compute Text Metrics");
  1823. #endif
  1824. // Element Ascender in line space
  1825. float elementAscender = m_textElementType == TMP_TextElementType.Character
  1826. ? elementAscentLine * currentElementScale / smallCapsMultiplier + m_baselineOffset
  1827. : elementAscentLine * currentElementScale + m_baselineOffset;
  1828. // Element Descender in line space
  1829. float elementDescender = m_textElementType == TMP_TextElementType.Character
  1830. ? elementDescentLine * currentElementScale / smallCapsMultiplier + m_baselineOffset
  1831. : elementDescentLine * currentElementScale + m_baselineOffset;
  1832. float adjustedAscender = elementAscender;
  1833. float adjustedDescender = elementDescender;
  1834. bool isFirstCharacterOfLine = m_characterCount == m_firstCharacterOfLine;
  1835. // Max line ascender and descender in line space
  1836. if (isFirstCharacterOfLine || isWhiteSpace == false)
  1837. {
  1838. // Special handling for Superscript and Subscript where we use the unadjusted line ascender and descender
  1839. if (m_baselineOffset != 0)
  1840. {
  1841. adjustedAscender = Mathf.Max((elementAscender - m_baselineOffset) / m_fontScaleMultiplier, adjustedAscender);
  1842. adjustedDescender = Mathf.Min((elementDescender - m_baselineOffset) / m_fontScaleMultiplier, adjustedDescender);
  1843. }
  1844. m_maxLineAscender = Mathf.Max(adjustedAscender, m_maxLineAscender);
  1845. m_maxLineDescender = Mathf.Min(adjustedDescender, m_maxLineDescender);
  1846. }
  1847. // Element Ascender and Descender in object space
  1848. if (isFirstCharacterOfLine || isWhiteSpace == false)
  1849. {
  1850. m_textInfo.characterInfo[m_characterCount].adjustedAscender = adjustedAscender;
  1851. m_textInfo.characterInfo[m_characterCount].adjustedDescender = adjustedDescender;
  1852. m_ElementAscender = m_textInfo.characterInfo[m_characterCount].ascender = elementAscender - m_lineOffset;
  1853. m_ElementDescender = m_textInfo.characterInfo[m_characterCount].descender = elementDescender - m_lineOffset;
  1854. }
  1855. else
  1856. {
  1857. m_textInfo.characterInfo[m_characterCount].adjustedAscender = m_maxLineAscender;
  1858. m_textInfo.characterInfo[m_characterCount].adjustedDescender = m_maxLineDescender;
  1859. m_ElementAscender = m_textInfo.characterInfo[m_characterCount].ascender = m_maxLineAscender - m_lineOffset;
  1860. m_ElementDescender = m_textInfo.characterInfo[m_characterCount].descender = m_maxLineDescender - m_lineOffset;
  1861. }
  1862. // Max text object ascender and cap height
  1863. if (m_lineNumber == 0 || m_isNewPage)
  1864. {
  1865. if (isFirstCharacterOfLine || isWhiteSpace == false)
  1866. {
  1867. m_maxTextAscender = m_maxLineAscender;
  1868. m_maxCapHeight = Mathf.Max(m_maxCapHeight, m_currentFontAsset.m_FaceInfo.capLine * currentElementScale / smallCapsMultiplier);
  1869. }
  1870. }
  1871. // Page ascender
  1872. if (m_lineOffset == 0)
  1873. {
  1874. if (isFirstCharacterOfLine || isWhiteSpace == false)
  1875. m_PageAscender = m_PageAscender > elementAscender ? m_PageAscender : elementAscender;
  1876. }
  1877. #if TMP_PROFILE_ON
  1878. Profiler.EndSample();
  1879. #endif
  1880. #endregion
  1881. // Set Characters to not visible by default.
  1882. m_textInfo.characterInfo[m_characterCount].isVisible = false;
  1883. bool isJustifiedOrFlush = (m_lineJustification & HorizontalAlignmentOptions.Flush) == HorizontalAlignmentOptions.Flush || (m_lineJustification & HorizontalAlignmentOptions.Justified) == HorizontalAlignmentOptions.Justified;
  1884. // Setup Mesh for visible text elements. ie. not a SPACE / LINEFEED / CARRIAGE RETURN.
  1885. #region Handle Visible Characters
  1886. if (charCode == 9 || (isWhiteSpace == false && charCode != 0x200B && charCode != 0xAD && charCode != 0x03) || (charCode == 0xAD && isSoftHyphenIgnored == false) || m_textElementType == TMP_TextElementType.Sprite)
  1887. {
  1888. #if TMP_PROFILE_ON
  1889. Profiler.BeginSample("TMP - Handle Visible Character");
  1890. #endif
  1891. m_textInfo.characterInfo[m_characterCount].isVisible = true;
  1892. #region Experimental Margin Shaper
  1893. //Vector2 shapedMargins;
  1894. //if (marginShaper)
  1895. //{
  1896. // shapedMargins = m_marginShaper.GetShapedMargins(m_textInfo.characterInfo[m_characterCount].baseLine);
  1897. // if (shapedMargins.x < margins.x)
  1898. // {
  1899. // shapedMargins.x = m_marginLeft;
  1900. // }
  1901. // else
  1902. // {
  1903. // shapedMargins.x += m_marginLeft - margins.x;
  1904. // }
  1905. // if (shapedMargins.y < margins.z)
  1906. // {
  1907. // shapedMargins.y = m_marginRight;
  1908. // }
  1909. // else
  1910. // {
  1911. // shapedMargins.y += m_marginRight - margins.z;
  1912. // }
  1913. //}
  1914. //else
  1915. //{
  1916. // shapedMargins.x = m_marginLeft;
  1917. // shapedMargins.y = m_marginRight;
  1918. //}
  1919. //width = marginWidth + 0.0001f - shapedMargins.x - shapedMargins.y;
  1920. //if (m_width != -1 && m_width < width)
  1921. //{
  1922. // width = m_width;
  1923. //}
  1924. //m_textInfo.lineInfo[m_lineNumber].marginLeft = shapedMargins.x;
  1925. #endregion
  1926. float marginLeft = m_marginLeft;
  1927. float marginRight = m_marginRight;
  1928. // Injected characters do not override margins
  1929. if (isInjectingCharacter)
  1930. {
  1931. marginLeft = m_textInfo.lineInfo[m_lineNumber].marginLeft;
  1932. marginRight = m_textInfo.lineInfo[m_lineNumber].marginRight;
  1933. }
  1934. widthOfTextArea = m_width != -1 ? Mathf.Min(marginWidth + 0.0001f - marginLeft - marginRight, m_width) : marginWidth + 0.0001f - marginLeft - marginRight;
  1935. // Calculate the line breaking width of the text.
  1936. float textWidth = Mathf.Abs(m_xAdvance) + (!m_isRightToLeft ? currentGlyphMetrics.horizontalAdvance : 0) * (1 - m_charWidthAdjDelta) * (charCode == 0xAD ? currentElementUnmodifiedScale : currentElementScale);
  1937. float textHeight = m_maxTextAscender - (m_maxLineDescender - m_lineOffset) + (m_lineOffset > 0 && m_IsDrivenLineSpacing == false ? m_maxLineAscender - m_startOfLineAscender : 0);
  1938. int testedCharacterCount = m_characterCount;
  1939. // Handling of current line Vertical Bounds
  1940. #region Current Line Vertical Bounds Check
  1941. if (textHeight > marginHeight + 0.0001f)
  1942. {
  1943. // Set isTextOverflowing and firstOverflowCharacterIndex
  1944. if (m_firstOverflowCharacterIndex == -1)
  1945. m_firstOverflowCharacterIndex = m_characterCount;
  1946. // Check if Auto-Size is enabled
  1947. if (m_enableAutoSizing)
  1948. {
  1949. // Handle Line spacing adjustments
  1950. #region Line Spacing Adjustments
  1951. if (m_lineSpacingDelta > m_lineSpacingMax && m_lineOffset > 0 && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  1952. {
  1953. float adjustmentDelta = (marginHeight - textHeight) / m_lineNumber;
  1954. m_lineSpacingDelta = Mathf.Max(m_lineSpacingDelta + adjustmentDelta / baseScale, m_lineSpacingMax);
  1955. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Line Spacing. Delta of [" + m_lineSpacingDelta.ToString("f3") + "].");
  1956. return;
  1957. }
  1958. #endregion
  1959. // Handle Text Auto-sizing resulting from text exceeding vertical bounds.
  1960. #region Text Auto-Sizing (Text greater than vertical bounds)
  1961. if (m_fontSize > m_fontSizeMin && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  1962. {
  1963. m_maxFontSize = m_fontSize;
  1964. float sizeDelta = Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
  1965. m_fontSize -= sizeDelta;
  1966. m_fontSize = Mathf.Max((int)(m_fontSize * 20 + 0.5f) / 20f, m_fontSizeMin);
  1967. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Point Size from [" + m_maxFontSize.ToString("f3") + "] to [" + m_fontSize.ToString("f3") + "] with delta of [" + sizeDelta.ToString("f3") + "].");
  1968. return;
  1969. }
  1970. #endregion Text Auto-Sizing
  1971. }
  1972. // Handle Vertical Overflow on current line
  1973. switch (m_overflowMode)
  1974. {
  1975. case TextOverflowModes.Overflow:
  1976. case TextOverflowModes.ScrollRect:
  1977. case TextOverflowModes.Masking:
  1978. // Nothing happens as vertical bounds are ignored in this mode.
  1979. break;
  1980. case TextOverflowModes.Truncate:
  1981. i = RestoreWordWrappingState(ref m_SavedLastValidState);
  1982. characterToSubstitute.index = testedCharacterCount;
  1983. characterToSubstitute.unicode = 0x03;
  1984. continue;
  1985. case TextOverflowModes.Ellipsis:
  1986. if (m_EllipsisInsertionCandidateStack.Count == 0)
  1987. {
  1988. i = -1;
  1989. m_characterCount = 0;
  1990. characterToSubstitute.index = 0;
  1991. characterToSubstitute.unicode = 0x03;
  1992. m_firstCharacterOfLine = 0;
  1993. continue;
  1994. }
  1995. var ellipsisState = m_EllipsisInsertionCandidateStack.Pop();
  1996. i = RestoreWordWrappingState(ref ellipsisState);
  1997. i -= 1;
  1998. m_characterCount -= 1;
  1999. characterToSubstitute.index = m_characterCount;
  2000. characterToSubstitute.unicode = 0x2026;
  2001. restoreCount += 1;
  2002. continue;
  2003. case TextOverflowModes.Linked:
  2004. i = RestoreWordWrappingState(ref m_SavedLastValidState);
  2005. if (m_linkedTextComponent != null)
  2006. {
  2007. m_linkedTextComponent.text = text;
  2008. m_linkedTextComponent.firstVisibleCharacter = m_characterCount;
  2009. m_linkedTextComponent.ForceMeshUpdate();
  2010. m_isTextTruncated = true;
  2011. }
  2012. // Truncate remaining text
  2013. characterToSubstitute.index = testedCharacterCount;
  2014. characterToSubstitute.unicode = 0x03;
  2015. continue;
  2016. case TextOverflowModes.Page:
  2017. // End layout of text if first character / page doesn't fit.
  2018. if (i < 0 || testedCharacterCount == 0)
  2019. {
  2020. i = -1;
  2021. m_characterCount = 0;
  2022. characterToSubstitute.index = 0;
  2023. characterToSubstitute.unicode = 0x03;
  2024. continue;
  2025. }
  2026. else if (m_maxLineAscender - m_maxLineDescender > marginHeight + 0.0001f)
  2027. {
  2028. // Current line exceeds the height of the text container
  2029. // as such we stop on the previous line.
  2030. i = RestoreWordWrappingState(ref m_SavedLineState);
  2031. characterToSubstitute.index = testedCharacterCount;
  2032. characterToSubstitute.unicode = 0x03;
  2033. continue;
  2034. }
  2035. // Go back to previous line and re-layout
  2036. i = RestoreWordWrappingState(ref m_SavedLineState);
  2037. m_isNewPage = true;
  2038. m_firstCharacterOfLine = m_characterCount;
  2039. m_maxLineAscender = k_LargeNegativeFloat;
  2040. m_maxLineDescender = k_LargePositiveFloat;
  2041. m_startOfLineAscender = 0;
  2042. m_xAdvance = 0 + tag_Indent;
  2043. m_lineOffset = 0;
  2044. m_maxTextAscender = 0;
  2045. m_PageAscender = 0;
  2046. m_lineNumber += 1;
  2047. m_pageNumber += 1;
  2048. // Should consider saving page data here
  2049. continue;
  2050. }
  2051. }
  2052. #endregion
  2053. // Handling of Horizontal Bounds
  2054. #region Current Line Horizontal Bounds Check
  2055. if (textWidth > widthOfTextArea * (isJustifiedOrFlush ? 1.05f : 1.0f))
  2056. {
  2057. #if TMP_PROFILE_ON
  2058. Profiler.BeginSample("TMP - Handle Horizontal Line Breaking");
  2059. #endif
  2060. // Handle Line Breaking (if still possible)
  2061. if (m_enableWordWrapping && m_characterCount != m_firstCharacterOfLine) // && isFirstWord == false)
  2062. {
  2063. // Restore state to previous safe line breaking
  2064. i = RestoreWordWrappingState(ref m_SavedWordWrapState);
  2065. // Compute potential new line offset in the event a line break is needed.
  2066. float lineOffsetDelta = 0;
  2067. if (m_lineHeight == TMP_Math.FLOAT_UNSET)
  2068. {
  2069. float ascender = m_textInfo.characterInfo[m_characterCount].adjustedAscender;
  2070. lineOffsetDelta = (m_lineOffset > 0 && m_IsDrivenLineSpacing == false ? m_maxLineAscender - m_startOfLineAscender : 0) - m_maxLineDescender + ascender + (lineGap + m_lineSpacingDelta) * baseScale + m_lineSpacing * currentEmScale;
  2071. }
  2072. else
  2073. {
  2074. lineOffsetDelta = m_lineHeight + m_lineSpacing * currentEmScale;
  2075. m_IsDrivenLineSpacing = true;
  2076. }
  2077. // Calculate new text height
  2078. float newTextHeight = m_maxTextAscender + lineOffsetDelta + m_lineOffset - m_textInfo.characterInfo[m_characterCount].adjustedDescender;
  2079. // Replace Soft Hyphen by Hyphen Minus 0x2D
  2080. #region Handle Soft Hyphenation
  2081. if (m_textInfo.characterInfo[m_characterCount - 1].character == 0xAD && isSoftHyphenIgnored == false)
  2082. {
  2083. // Only inject Hyphen Minus if new line is possible
  2084. if (m_overflowMode == TextOverflowModes.Overflow || newTextHeight < marginHeight + 0.0001f)
  2085. {
  2086. characterToSubstitute.index = m_characterCount - 1;
  2087. characterToSubstitute.unicode = 0x2D;
  2088. i -= 1;
  2089. m_characterCount -= 1;
  2090. continue;
  2091. }
  2092. }
  2093. isSoftHyphenIgnored = false;
  2094. // Ignore Soft Hyphen to prevent it from wrapping
  2095. if (m_textInfo.characterInfo[m_characterCount].character == 0xAD)
  2096. {
  2097. isSoftHyphenIgnored = true;
  2098. continue;
  2099. }
  2100. #endregion
  2101. // Adjust character spacing before breaking up word if auto size is enabled
  2102. if (m_enableAutoSizing && isFirstWordOfLine)
  2103. {
  2104. // Handle Character Width Adjustments
  2105. #region Character Width Adjustments
  2106. if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100 && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  2107. {
  2108. float adjustedTextWidth = textWidth;
  2109. // Determine full width of the text
  2110. if (m_charWidthAdjDelta > 0)
  2111. adjustedTextWidth /= 1f - m_charWidthAdjDelta;
  2112. float adjustmentDelta = textWidth - (widthOfTextArea - 0.0001f) * (isJustifiedOrFlush ? 1.05f : 1.0f);
  2113. m_charWidthAdjDelta += adjustmentDelta / adjustedTextWidth;
  2114. m_charWidthAdjDelta = Mathf.Min(m_charWidthAdjDelta, m_charWidthMaxAdj / 100);
  2115. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Character Width by " + (m_charWidthAdjDelta * 100) + "%");
  2116. return;
  2117. }
  2118. #endregion
  2119. // Handle Text Auto-sizing resulting from text exceeding vertical bounds.
  2120. #region Text Auto-Sizing (Text greater than vertical bounds)
  2121. if (m_fontSize > m_fontSizeMin && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  2122. {
  2123. m_maxFontSize = m_fontSize;
  2124. float sizeDelta = Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
  2125. m_fontSize -= sizeDelta;
  2126. m_fontSize = Mathf.Max((int)(m_fontSize * 20 + 0.5f) / 20f, m_fontSizeMin);
  2127. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Point Size from [" + m_maxFontSize.ToString("f3") + "] to [" + m_fontSize.ToString("f3") + "] with delta of [" + sizeDelta.ToString("f3") + "].");
  2128. return;
  2129. }
  2130. #endregion Text Auto-Sizing
  2131. }
  2132. // Special handling if first word of line and non breaking space
  2133. int savedSoftLineBreakingSpace = m_SavedSoftLineBreakState.previous_WordBreak;
  2134. if (isFirstWordOfLine && savedSoftLineBreakingSpace != -1)
  2135. {
  2136. if (savedSoftLineBreakingSpace != lastSoftLineBreak)
  2137. {
  2138. i = RestoreWordWrappingState(ref m_SavedSoftLineBreakState);
  2139. lastSoftLineBreak = savedSoftLineBreakingSpace;
  2140. // check if soft hyphen
  2141. if (m_textInfo.characterInfo[m_characterCount - 1].character == 0xAD)
  2142. {
  2143. characterToSubstitute.index = m_characterCount - 1;
  2144. characterToSubstitute.unicode = 0x2D;
  2145. i -= 1;
  2146. m_characterCount -= 1;
  2147. continue;
  2148. }
  2149. }
  2150. }
  2151. // Determine if new line of text would exceed the vertical bounds of text container
  2152. if (newTextHeight > marginHeight + 0.0001f)
  2153. {
  2154. // Set isTextOverflowing and firstOverflowCharacterIndex
  2155. if (m_firstOverflowCharacterIndex == -1)
  2156. m_firstOverflowCharacterIndex = m_characterCount;
  2157. // Check if Auto-Size is enabled
  2158. if (m_enableAutoSizing)
  2159. {
  2160. // Handle Line spacing adjustments
  2161. #region Line Spacing Adjustments
  2162. if (m_lineSpacingDelta > m_lineSpacingMax && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  2163. {
  2164. float adjustmentDelta = (marginHeight - newTextHeight) / (m_lineNumber + 1);
  2165. m_lineSpacingDelta = Mathf.Max(m_lineSpacingDelta + adjustmentDelta / baseScale, m_lineSpacingMax);
  2166. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Line Spacing. Delta of [" + m_lineSpacingDelta.ToString("f3") + "].");
  2167. return;
  2168. }
  2169. #endregion
  2170. // Handle Character Width Adjustments
  2171. #region Character Width Adjustments
  2172. if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100 && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  2173. {
  2174. float adjustedTextWidth = textWidth;
  2175. // Determine full width of the text
  2176. if (m_charWidthAdjDelta > 0)
  2177. adjustedTextWidth /= 1f - m_charWidthAdjDelta;
  2178. float adjustmentDelta = textWidth - (widthOfTextArea - 0.0001f) * (isJustifiedOrFlush ? 1.05f : 1.0f);
  2179. m_charWidthAdjDelta += adjustmentDelta / adjustedTextWidth;
  2180. m_charWidthAdjDelta = Mathf.Min(m_charWidthAdjDelta, m_charWidthMaxAdj / 100);
  2181. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Character Width by " + (m_charWidthAdjDelta * 100) + "%");
  2182. return;
  2183. }
  2184. #endregion
  2185. // Handle Text Auto-sizing resulting from text exceeding vertical bounds.
  2186. #region Text Auto-Sizing (Text greater than vertical bounds)
  2187. if (m_fontSize > m_fontSizeMin && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  2188. {
  2189. m_maxFontSize = m_fontSize;
  2190. float sizeDelta = Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
  2191. m_fontSize -= sizeDelta;
  2192. m_fontSize = Mathf.Max((int)(m_fontSize * 20 + 0.5f) / 20f, m_fontSizeMin);
  2193. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Point Size from [" + m_maxFontSize.ToString("f3") + "] to [" + m_fontSize.ToString("f3") + "] with delta of [" + sizeDelta.ToString("f3") + "].");
  2194. return;
  2195. }
  2196. #endregion Text Auto-Sizing
  2197. }
  2198. // Check Text Overflow Modes
  2199. switch (m_overflowMode)
  2200. {
  2201. case TextOverflowModes.Overflow:
  2202. case TextOverflowModes.ScrollRect:
  2203. case TextOverflowModes.Masking:
  2204. #if TMP_PROFILE_ON
  2205. Profiler.BeginSample("TMP - InsertNewLine()");
  2206. #endif
  2207. InsertNewLine(i, baseScale, currentElementScale, currentEmScale, m_GlyphHorizontalAdvanceAdjustment, boldSpacingAdjustment, characterSpacingAdjustment, widthOfTextArea, lineGap, ref isMaxVisibleDescenderSet, ref maxVisibleDescender);
  2208. isStartOfNewLine = true;
  2209. isFirstWordOfLine = true;
  2210. #if TMP_PROFILE_ON
  2211. // End Sampling of InsertNewLine()
  2212. Profiler.EndSample();
  2213. // End Sampling of Horizontal Line Breaking
  2214. Profiler.EndSample();
  2215. // End Sampling of Visible Character
  2216. Profiler.EndSample();
  2217. #endif
  2218. continue;
  2219. case TextOverflowModes.Truncate:
  2220. i = RestoreWordWrappingState(ref m_SavedLastValidState);
  2221. characterToSubstitute.index = testedCharacterCount;
  2222. characterToSubstitute.unicode = 0x03;
  2223. continue;
  2224. case TextOverflowModes.Ellipsis:
  2225. if (m_EllipsisInsertionCandidateStack.Count == 0)
  2226. {
  2227. i = -1;
  2228. m_characterCount = 0;
  2229. characterToSubstitute.index = 0;
  2230. characterToSubstitute.unicode = 0x03;
  2231. m_firstCharacterOfLine = 0;
  2232. continue;
  2233. }
  2234. var ellipsisState = m_EllipsisInsertionCandidateStack.Pop();
  2235. i = RestoreWordWrappingState(ref ellipsisState);
  2236. i -= 1;
  2237. m_characterCount -= 1;
  2238. characterToSubstitute.index = m_characterCount;
  2239. characterToSubstitute.unicode = 0x2026;
  2240. restoreCount += 1;
  2241. continue;
  2242. case TextOverflowModes.Linked:
  2243. if (m_linkedTextComponent != null)
  2244. {
  2245. m_linkedTextComponent.text = text;
  2246. m_linkedTextComponent.firstVisibleCharacter = m_characterCount;
  2247. m_linkedTextComponent.ForceMeshUpdate();
  2248. m_isTextTruncated = true;
  2249. }
  2250. // Truncate remaining text
  2251. characterToSubstitute.index = m_characterCount;
  2252. characterToSubstitute.unicode = 0x03;
  2253. continue;
  2254. case TextOverflowModes.Page:
  2255. // Add new page
  2256. m_isNewPage = true;
  2257. InsertNewLine(i, baseScale, currentElementScale, currentEmScale, m_GlyphHorizontalAdvanceAdjustment, boldSpacingAdjustment, characterSpacingAdjustment, widthOfTextArea, lineGap, ref isMaxVisibleDescenderSet, ref maxVisibleDescender);
  2258. m_startOfLineAscender = 0;
  2259. m_lineOffset = 0;
  2260. m_maxTextAscender = 0;
  2261. m_PageAscender = 0;
  2262. m_pageNumber += 1;
  2263. isStartOfNewLine = true;
  2264. isFirstWordOfLine = true;
  2265. continue;
  2266. }
  2267. }
  2268. else
  2269. {
  2270. //if (m_enableAutoSizing && isFirstWordOfLine)
  2271. //{
  2272. // // Handle Character Width Adjustments
  2273. // #region Character Width Adjustments
  2274. // if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100 && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  2275. // {
  2276. // //m_AutoSizeIterationCount = 0;
  2277. // float adjustedTextWidth = textWidth;
  2278. // // Determine full width of the text
  2279. // if (m_charWidthAdjDelta > 0)
  2280. // adjustedTextWidth /= 1f - m_charWidthAdjDelta;
  2281. // float adjustmentDelta = textWidth - (widthOfTextArea - 0.0001f) * (isJustifiedOrFlush ? 1.05f : 1.0f);
  2282. // m_charWidthAdjDelta += adjustmentDelta / adjustedTextWidth;
  2283. // m_charWidthAdjDelta = Mathf.Min(m_charWidthAdjDelta, m_charWidthMaxAdj / 100);
  2284. // //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Character Width by " + (m_charWidthAdjDelta * 100) + "%");
  2285. // GenerateTextMesh();
  2286. // return;
  2287. // }
  2288. // #endregion
  2289. //}
  2290. #if TMP_PROFILE_ON
  2291. Profiler.BeginSample("TMP - InsertNewLine()");
  2292. #endif
  2293. // New line of text does not exceed vertical bounds of text container
  2294. InsertNewLine(i, baseScale, currentElementScale, currentEmScale, m_GlyphHorizontalAdvanceAdjustment, boldSpacingAdjustment, characterSpacingAdjustment, widthOfTextArea, lineGap, ref isMaxVisibleDescenderSet, ref maxVisibleDescender);
  2295. isStartOfNewLine = true;
  2296. isFirstWordOfLine = true;
  2297. #if TMP_PROFILE_ON
  2298. // End Sampling of InsertNewLine()
  2299. Profiler.EndSample();
  2300. // End Sampling of Horizontal Line Breaking
  2301. Profiler.EndSample();
  2302. // End Sampling of Visible Character
  2303. Profiler.EndSample();
  2304. #endif
  2305. continue;
  2306. }
  2307. }
  2308. else
  2309. {
  2310. if (m_enableAutoSizing && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  2311. {
  2312. // Handle Character Width Adjustments
  2313. #region Character Width Adjustments
  2314. if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100)
  2315. {
  2316. float adjustedTextWidth = textWidth;
  2317. // Determine full width of the text
  2318. if (m_charWidthAdjDelta > 0)
  2319. adjustedTextWidth /= 1f - m_charWidthAdjDelta;
  2320. float adjustmentDelta = textWidth - (widthOfTextArea - 0.0001f) * (isJustifiedOrFlush ? 1.05f : 1.0f);
  2321. m_charWidthAdjDelta += adjustmentDelta / adjustedTextWidth;
  2322. m_charWidthAdjDelta = Mathf.Min(m_charWidthAdjDelta, m_charWidthMaxAdj / 100);
  2323. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Character Width by " + (m_charWidthAdjDelta * 100) + "%");
  2324. return;
  2325. }
  2326. #endregion
  2327. // Handle Text Auto-sizing resulting from text exceeding horizontal bounds.
  2328. #region Text Exceeds Horizontal Bounds - Reducing Point Size
  2329. if (m_fontSize > m_fontSizeMin)
  2330. {
  2331. // Reset character width adjustment delta
  2332. //m_charWidthAdjDelta = 0;
  2333. // Adjust Point Size
  2334. m_maxFontSize = m_fontSize;
  2335. float sizeDelta = Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
  2336. m_fontSize -= sizeDelta;
  2337. m_fontSize = Mathf.Max((int)(m_fontSize * 20 + 0.5f) / 20f, m_fontSizeMin);
  2338. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Point Size from [" + m_maxFontSize.ToString("f3") + "] to [" + m_fontSize.ToString("f3") + "] with delta of [" + sizeDelta.ToString("f3") + "].");
  2339. return;
  2340. }
  2341. #endregion
  2342. }
  2343. // Check Text Overflow Modes
  2344. switch (m_overflowMode)
  2345. {
  2346. case TextOverflowModes.Overflow:
  2347. case TextOverflowModes.ScrollRect:
  2348. case TextOverflowModes.Masking:
  2349. // Nothing happens as horizontal bounds are ignored in this mode.
  2350. break;
  2351. case TextOverflowModes.Truncate:
  2352. i = RestoreWordWrappingState(ref m_SavedWordWrapState);
  2353. characterToSubstitute.index = testedCharacterCount;
  2354. characterToSubstitute.unicode = 0x03;
  2355. continue;
  2356. case TextOverflowModes.Ellipsis:
  2357. if (m_EllipsisInsertionCandidateStack.Count == 0)
  2358. {
  2359. i = -1;
  2360. m_characterCount = 0;
  2361. characterToSubstitute.index = 0;
  2362. characterToSubstitute.unicode = 0x03;
  2363. m_firstCharacterOfLine = 0;
  2364. continue;
  2365. }
  2366. var ellipsisState = m_EllipsisInsertionCandidateStack.Pop();
  2367. i = RestoreWordWrappingState(ref ellipsisState);
  2368. i -= 1;
  2369. m_characterCount -= 1;
  2370. characterToSubstitute.index = m_characterCount;
  2371. characterToSubstitute.unicode = 0x2026;
  2372. restoreCount += 1;
  2373. continue;
  2374. case TextOverflowModes.Linked:
  2375. i = RestoreWordWrappingState(ref m_SavedWordWrapState);
  2376. if (m_linkedTextComponent != null)
  2377. {
  2378. m_linkedTextComponent.text = text;
  2379. m_linkedTextComponent.firstVisibleCharacter = m_characterCount;
  2380. m_linkedTextComponent.ForceMeshUpdate();
  2381. m_isTextTruncated = true;
  2382. }
  2383. // Truncate text the overflows the vertical bounds
  2384. characterToSubstitute.index = m_characterCount;
  2385. characterToSubstitute.unicode = 0x03;
  2386. continue;
  2387. }
  2388. }
  2389. #if TMP_PROFILE_ON
  2390. // End Sampling of Horizontal Line Breaking
  2391. Profiler.EndSample();
  2392. #endif
  2393. }
  2394. #endregion
  2395. // Special handling of characters that are not ignored at the end of a line.
  2396. if (charCode == 9)
  2397. {
  2398. m_textInfo.characterInfo[m_characterCount].isVisible = false;
  2399. m_lastVisibleCharacterOfLine = m_characterCount;
  2400. m_textInfo.lineInfo[m_lineNumber].spaceCount += 1;
  2401. m_textInfo.spaceCount += 1;
  2402. }
  2403. else if (charCode == 0xAD)
  2404. {
  2405. m_textInfo.characterInfo[m_characterCount].isVisible = false;
  2406. }
  2407. else
  2408. {
  2409. // Determine Vertex Color
  2410. if (m_overrideHtmlColors)
  2411. vertexColor = m_fontColor32;
  2412. else
  2413. vertexColor = m_htmlColor;
  2414. #if TMP_PROFILE_ON
  2415. Profiler.BeginSample("TMP - Save Glyph Vertex Data");
  2416. #endif
  2417. // Store Character & Sprite Vertex Information
  2418. if (m_textElementType == TMP_TextElementType.Character)
  2419. {
  2420. // Save Character Vertex Data
  2421. SaveGlyphVertexInfo(padding, style_padding, vertexColor);
  2422. }
  2423. else if (m_textElementType == TMP_TextElementType.Sprite)
  2424. {
  2425. SaveSpriteVertexInfo(vertexColor);
  2426. }
  2427. #if TMP_PROFILE_ON
  2428. Profiler.EndSample();
  2429. #endif
  2430. if (isStartOfNewLine)
  2431. {
  2432. isStartOfNewLine = false;
  2433. m_firstVisibleCharacterOfLine = m_characterCount;
  2434. }
  2435. m_lineVisibleCharacterCount += 1;
  2436. m_lastVisibleCharacterOfLine = m_characterCount;
  2437. m_textInfo.lineInfo[m_lineNumber].marginLeft = marginLeft;
  2438. m_textInfo.lineInfo[m_lineNumber].marginRight = marginRight;
  2439. }
  2440. #if TMP_PROFILE_ON
  2441. Profiler.EndSample();
  2442. #endif
  2443. }
  2444. else
  2445. {
  2446. #if TMP_PROFILE_ON
  2447. Profiler.BeginSample("TMP - Handle White Space & Non Visible Character");
  2448. #endif
  2449. // This is white spacing / non visible characters.
  2450. // Track # of spaces per line which is used for line justification.
  2451. if ((charCode == 10 || charCode == 11 || charCode == 0xA0 || charCode == 0x2007 || charCode == 0x2028 || charCode == 0x2029 || char.IsSeparator((char)charCode)) && charCode != 0xAD && charCode != 0x200B && charCode != 0x2060)
  2452. {
  2453. m_textInfo.lineInfo[m_lineNumber].spaceCount += 1;
  2454. m_textInfo.spaceCount += 1;
  2455. }
  2456. if (charCode == 0xA0)
  2457. m_textInfo.lineInfo[m_lineNumber].controlCharacterCount += 1;
  2458. #if TMP_PROFILE_ON
  2459. Profiler.EndSample();
  2460. #endif
  2461. }
  2462. #endregion Handle Visible Characters
  2463. // Tracking of potential insertion positions for Ellipsis character
  2464. #region Track Potential Insertion Location for Ellipsis
  2465. if (m_overflowMode == TextOverflowModes.Ellipsis && (isInjectingCharacter == false || charCode == 0x2D))
  2466. {
  2467. float fontScale = m_currentFontSize / m_Ellipsis.fontAsset.m_FaceInfo.pointSize * m_Ellipsis.fontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f);
  2468. float scale = fontScale * m_fontScaleMultiplier * m_Ellipsis.character.m_Scale * m_Ellipsis.character.m_Glyph.scale;
  2469. float marginLeft = m_marginLeft;
  2470. float marginRight = m_marginRight;
  2471. // Use the scale and margins of the previous character if Line Feed (LF) is not the first character of a line.
  2472. if (charCode == 0x0A && m_characterCount != m_firstCharacterOfLine)
  2473. {
  2474. fontScale = m_textInfo.characterInfo[m_characterCount - 1].pointSize / m_Ellipsis.fontAsset.m_FaceInfo.pointSize * m_Ellipsis.fontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f);
  2475. scale = fontScale * m_fontScaleMultiplier * m_Ellipsis.character.m_Scale * m_Ellipsis.character.m_Glyph.scale;
  2476. marginLeft = m_textInfo.lineInfo[m_lineNumber].marginLeft;
  2477. marginRight = m_textInfo.lineInfo[m_lineNumber].marginRight;
  2478. }
  2479. float textHeight = m_maxTextAscender - (m_maxLineDescender - m_lineOffset) + (m_lineOffset > 0 && m_IsDrivenLineSpacing == false ? m_maxLineAscender - m_startOfLineAscender : 0);
  2480. float textWidth = Mathf.Abs(m_xAdvance) + (!m_isRightToLeft ? m_Ellipsis.character.m_Glyph.metrics.horizontalAdvance : 0) * (1 - m_charWidthAdjDelta) * scale;
  2481. float widthOfTextAreaForEllipsis = m_width != -1 ? Mathf.Min(marginWidth + 0.0001f - marginLeft - marginRight, m_width) : marginWidth + 0.0001f - marginLeft - marginRight;
  2482. if (textWidth < widthOfTextAreaForEllipsis * (isJustifiedOrFlush ? 1.05f : 1.0f) && textHeight < marginHeight + 0.0001f)
  2483. {
  2484. SaveWordWrappingState(ref m_SavedEllipsisState, i, m_characterCount);
  2485. m_EllipsisInsertionCandidateStack.Push(m_SavedEllipsisState);
  2486. }
  2487. }
  2488. #endregion
  2489. // Store Rectangle positions for each Character.
  2490. #region Store Character Data
  2491. m_textInfo.characterInfo[m_characterCount].lineNumber = m_lineNumber;
  2492. m_textInfo.characterInfo[m_characterCount].pageNumber = m_pageNumber;
  2493. if (charCode != 10 && charCode != 11 && charCode != 13 && isInjectingCharacter == false /* && charCode != 8230 */ || m_textInfo.lineInfo[m_lineNumber].characterCount == 1)
  2494. m_textInfo.lineInfo[m_lineNumber].alignment = m_lineJustification;
  2495. #endregion Store Character Data
  2496. // Handle xAdvance & Tabulation Stops. Tab stops at every 25% of Font Size.
  2497. #region XAdvance, Tabulation & Stops
  2498. #if TMP_PROFILE_ON
  2499. Profiler.BeginSample("TMP - Handle Advance & Tabulation");
  2500. #endif
  2501. if (charCode == 9)
  2502. {
  2503. float tabSize = m_currentFontAsset.m_FaceInfo.tabWidth * m_currentFontAsset.tabSize * currentElementScale;
  2504. float tabs = Mathf.Ceil(m_xAdvance / tabSize) * tabSize;
  2505. m_xAdvance = tabs > m_xAdvance ? tabs : m_xAdvance + tabSize;
  2506. }
  2507. else if (m_monoSpacing != 0)
  2508. {
  2509. m_xAdvance += (m_monoSpacing - monoAdvance + ((m_currentFontAsset.normalSpacingOffset + characterSpacingAdjustment) * currentEmScale) + m_cSpacing) * (1 - m_charWidthAdjDelta);
  2510. if (isWhiteSpace || charCode == 0x200B)
  2511. m_xAdvance += m_wordSpacing * currentEmScale;
  2512. }
  2513. else if (m_isRightToLeft)
  2514. {
  2515. m_xAdvance -= (((glyphAdjustments.m_XAdvance + boldSpacingAdjustment) * currentElementScale + (m_currentFontAsset.normalSpacingOffset + characterSpacingAdjustment) * currentEmScale + m_cSpacing) * (1 - m_charWidthAdjDelta));
  2516. if (isWhiteSpace || charCode == 0x200B)
  2517. m_xAdvance -= m_wordSpacing * currentEmScale;
  2518. }
  2519. else
  2520. {
  2521. float scaleFXMultiplier = 1;
  2522. if (m_isFXMatrixSet) scaleFXMultiplier = m_FXMatrix.lossyScale.x;
  2523. m_xAdvance += ((currentGlyphMetrics.horizontalAdvance * scaleFXMultiplier + glyphAdjustments.m_XAdvance + boldSpacingAdjustment) * currentElementScale + (m_currentFontAsset.normalSpacingOffset + characterSpacingAdjustment) * currentEmScale + m_cSpacing) * (1 - m_charWidthAdjDelta);
  2524. if (isWhiteSpace || charCode == 0x200B)
  2525. m_xAdvance += m_wordSpacing * currentEmScale;
  2526. }
  2527. // Store xAdvance information
  2528. m_textInfo.characterInfo[m_characterCount].xAdvance = m_xAdvance;
  2529. #if TMP_PROFILE_ON
  2530. Profiler.EndSample();
  2531. #endif
  2532. #endregion Tabulation & Stops
  2533. // Handle Carriage Return
  2534. #region Carriage Return
  2535. if (charCode == 13)
  2536. {
  2537. #if TMP_PROFILE_ON
  2538. Profiler.BeginSample("TMP - Handle Carriage Return");
  2539. #endif
  2540. m_xAdvance = 0 + tag_Indent;
  2541. #if TMP_PROFILE_ON
  2542. Profiler.EndSample();
  2543. #endif
  2544. }
  2545. #endregion Carriage Return
  2546. // Handle Line Spacing Adjustments + Word Wrapping & special case for last line.
  2547. #region Check for Line Feed and Last Character
  2548. if (charCode == 10 || charCode == 11 || charCode == 0x03 || charCode == 0x2028 || charCode == 0x2029 || (charCode == 0x2D && isInjectingCharacter) || m_characterCount == totalCharacterCount - 1)
  2549. {
  2550. #if TMP_PROFILE_ON
  2551. Profiler.BeginSample("TMP - Handle Line & Text Termination");
  2552. #endif
  2553. // Adjust current line spacing (if necessary) before inserting new line
  2554. float baselineAdjustmentDelta = m_maxLineAscender - m_startOfLineAscender;
  2555. if (m_lineOffset > 0 && Math.Abs(baselineAdjustmentDelta) > 0.01f && m_IsDrivenLineSpacing == false && !m_isNewPage)
  2556. {
  2557. //Debug.Log("Line Feed - Adjusting Line Spacing on line #" + m_lineNumber);
  2558. AdjustLineOffset(m_firstCharacterOfLine, m_characterCount, baselineAdjustmentDelta);
  2559. m_ElementDescender -= baselineAdjustmentDelta;
  2560. m_lineOffset += baselineAdjustmentDelta;
  2561. // Adjust saved ellipsis state only if we are adjusting the same line number
  2562. if (m_SavedEllipsisState.lineNumber == m_lineNumber)
  2563. {
  2564. m_SavedEllipsisState = m_EllipsisInsertionCandidateStack.Pop();
  2565. m_SavedEllipsisState.startOfLineAscender += baselineAdjustmentDelta;
  2566. m_SavedEllipsisState.lineOffset += baselineAdjustmentDelta;
  2567. m_EllipsisInsertionCandidateStack.Push(m_SavedEllipsisState);
  2568. }
  2569. }
  2570. m_isNewPage = false;
  2571. // Calculate lineAscender & make sure if last character is superscript or subscript that we check that as well.
  2572. float lineAscender = m_maxLineAscender - m_lineOffset;
  2573. float lineDescender = m_maxLineDescender - m_lineOffset;
  2574. // Update maxDescender and maxVisibleDescender
  2575. m_ElementDescender = m_ElementDescender < lineDescender ? m_ElementDescender : lineDescender;
  2576. if (!isMaxVisibleDescenderSet)
  2577. maxVisibleDescender = m_ElementDescender;
  2578. if (m_useMaxVisibleDescender && (m_characterCount >= m_maxVisibleCharacters || m_lineNumber >= m_maxVisibleLines))
  2579. isMaxVisibleDescenderSet = true;
  2580. // Save Line Information
  2581. m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex = m_firstCharacterOfLine;
  2582. m_textInfo.lineInfo[m_lineNumber].firstVisibleCharacterIndex = m_firstVisibleCharacterOfLine = m_firstCharacterOfLine > m_firstVisibleCharacterOfLine ? m_firstCharacterOfLine : m_firstVisibleCharacterOfLine;
  2583. m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex = m_lastCharacterOfLine = m_characterCount;
  2584. m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex = m_lastVisibleCharacterOfLine = m_lastVisibleCharacterOfLine < m_firstVisibleCharacterOfLine ? m_firstVisibleCharacterOfLine : m_lastVisibleCharacterOfLine;
  2585. m_textInfo.lineInfo[m_lineNumber].characterCount = m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex - m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex + 1;
  2586. m_textInfo.lineInfo[m_lineNumber].visibleCharacterCount = m_lineVisibleCharacterCount;
  2587. m_textInfo.lineInfo[m_lineNumber].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_firstVisibleCharacterOfLine].bottomLeft.x, lineDescender);
  2588. m_textInfo.lineInfo[m_lineNumber].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].topRight.x, lineAscender);
  2589. m_textInfo.lineInfo[m_lineNumber].length = m_textInfo.lineInfo[m_lineNumber].lineExtents.max.x - (padding * currentElementScale);
  2590. m_textInfo.lineInfo[m_lineNumber].width = widthOfTextArea;
  2591. if (m_textInfo.lineInfo[m_lineNumber].characterCount == 1)
  2592. m_textInfo.lineInfo[m_lineNumber].alignment = m_lineJustification;
  2593. float maxAdvanceOffset = (boldSpacingAdjustment * currentElementScale + (m_currentFontAsset.normalSpacingOffset + characterSpacingAdjustment) * currentEmScale - m_cSpacing) * (1 - m_charWidthAdjDelta);
  2594. if (m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].isVisible)
  2595. m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].xAdvance + (m_isRightToLeft ? maxAdvanceOffset : - maxAdvanceOffset);
  2596. else
  2597. m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastCharacterOfLine].xAdvance + (m_isRightToLeft ? maxAdvanceOffset : - maxAdvanceOffset);
  2598. m_textInfo.lineInfo[m_lineNumber].baseline = 0 - m_lineOffset;
  2599. m_textInfo.lineInfo[m_lineNumber].ascender = lineAscender;
  2600. m_textInfo.lineInfo[m_lineNumber].descender = lineDescender;
  2601. m_textInfo.lineInfo[m_lineNumber].lineHeight = lineAscender - lineDescender + lineGap * baseScale;
  2602. // Add new line if not last line or character.
  2603. if (charCode == 10 || charCode == 11 || charCode == 0x2D || charCode == 0x2028 || charCode == 0x2029)
  2604. {
  2605. // Store the state of the line before starting on the new line.
  2606. SaveWordWrappingState(ref m_SavedLineState, i, m_characterCount);
  2607. m_lineNumber += 1;
  2608. isStartOfNewLine = true;
  2609. ignoreNonBreakingSpace = false;
  2610. isFirstWordOfLine = true;
  2611. m_firstCharacterOfLine = m_characterCount + 1;
  2612. m_lineVisibleCharacterCount = 0;
  2613. // Check to make sure Array is large enough to hold a new line.
  2614. if (m_lineNumber >= m_textInfo.lineInfo.Length)
  2615. ResizeLineExtents(m_lineNumber);
  2616. float lastVisibleAscender = m_textInfo.characterInfo[m_characterCount].adjustedAscender;
  2617. // Apply Line Spacing with special handling for VT char(11)
  2618. if (m_lineHeight == TMP_Math.FLOAT_UNSET)
  2619. {
  2620. float lineOffsetDelta = 0 - m_maxLineDescender + lastVisibleAscender + (lineGap + m_lineSpacingDelta) * baseScale + (m_lineSpacing + (charCode == 10 || charCode == 0x2029 ? m_paragraphSpacing : 0)) * currentEmScale;
  2621. m_lineOffset += lineOffsetDelta;
  2622. m_IsDrivenLineSpacing = false;
  2623. }
  2624. else
  2625. {
  2626. m_lineOffset += m_lineHeight + (m_lineSpacing + (charCode == 10 || charCode == 0x2029 ? m_paragraphSpacing : 0)) * currentEmScale;
  2627. m_IsDrivenLineSpacing = true;
  2628. }
  2629. m_maxLineAscender = k_LargeNegativeFloat;
  2630. m_maxLineDescender = k_LargePositiveFloat;
  2631. m_startOfLineAscender = lastVisibleAscender;
  2632. m_xAdvance = 0 + tag_LineIndent + tag_Indent;
  2633. SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
  2634. SaveWordWrappingState(ref m_SavedLastValidState, i, m_characterCount);
  2635. m_characterCount += 1;
  2636. #if TMP_PROFILE_ON
  2637. Profiler.EndSample();
  2638. #endif
  2639. continue;
  2640. }
  2641. // If End of Text
  2642. if (charCode == 0x03)
  2643. i = m_InternalParsingBuffer.Length;
  2644. #if TMP_PROFILE_ON
  2645. Profiler.EndSample();
  2646. #endif
  2647. }
  2648. #endregion Check for Linefeed or Last Character
  2649. // Store Rectangle positions for each Character.
  2650. #region Save CharacterInfo for the current character.
  2651. #if TMP_PROFILE_ON
  2652. Profiler.BeginSample("TMP - Save Character & Page Info");
  2653. #endif
  2654. // Determine the bounds of the Mesh.
  2655. if (m_textInfo.characterInfo[m_characterCount].isVisible)
  2656. {
  2657. m_meshExtents.min.x = Mathf.Min(m_meshExtents.min.x, m_textInfo.characterInfo[m_characterCount].bottomLeft.x);
  2658. m_meshExtents.min.y = Mathf.Min(m_meshExtents.min.y, m_textInfo.characterInfo[m_characterCount].bottomLeft.y);
  2659. m_meshExtents.max.x = Mathf.Max(m_meshExtents.max.x, m_textInfo.characterInfo[m_characterCount].topRight.x);
  2660. m_meshExtents.max.y = Mathf.Max(m_meshExtents.max.y, m_textInfo.characterInfo[m_characterCount].topRight.y);
  2661. //m_meshExtents.min = new Vector2(Mathf.Min(m_meshExtents.min.x, m_textInfo.characterInfo[m_characterCount].bottomLeft.x), Mathf.Min(m_meshExtents.min.y, m_textInfo.characterInfo[m_characterCount].bottomLeft.y));
  2662. //m_meshExtents.max = new Vector2(Mathf.Max(m_meshExtents.max.x, m_textInfo.characterInfo[m_characterCount].topRight.x), Mathf.Max(m_meshExtents.max.y, m_textInfo.characterInfo[m_characterCount].topRight.y));
  2663. }
  2664. // Save pageInfo Data
  2665. if (m_overflowMode == TextOverflowModes.Page && charCode != 10 && charCode != 11 && charCode != 13 && charCode != 0x2028 && charCode != 0x2029) // && m_pageNumber < 16)
  2666. {
  2667. // Check if we need to increase allocations for the pageInfo array.
  2668. if (m_pageNumber + 1 > m_textInfo.pageInfo.Length)
  2669. TMP_TextInfo.Resize(ref m_textInfo.pageInfo, m_pageNumber + 1, true);
  2670. m_textInfo.pageInfo[m_pageNumber].ascender = m_PageAscender;
  2671. m_textInfo.pageInfo[m_pageNumber].descender = m_ElementDescender < m_textInfo.pageInfo[m_pageNumber].descender
  2672. ? m_ElementDescender
  2673. : m_textInfo.pageInfo[m_pageNumber].descender;
  2674. if (m_pageNumber == 0 && m_characterCount == 0)
  2675. m_textInfo.pageInfo[m_pageNumber].firstCharacterIndex = m_characterCount;
  2676. else if (m_characterCount > 0 && m_pageNumber != m_textInfo.characterInfo[m_characterCount - 1].pageNumber)
  2677. {
  2678. m_textInfo.pageInfo[m_pageNumber - 1].lastCharacterIndex = m_characterCount - 1;
  2679. m_textInfo.pageInfo[m_pageNumber].firstCharacterIndex = m_characterCount;
  2680. }
  2681. else if (m_characterCount == totalCharacterCount - 1)
  2682. m_textInfo.pageInfo[m_pageNumber].lastCharacterIndex = m_characterCount;
  2683. }
  2684. #if TMP_PROFILE_ON
  2685. Profiler.EndSample();
  2686. #endif
  2687. #endregion Saving CharacterInfo
  2688. // Save State of Mesh Creation for handling of Word Wrapping
  2689. #region Save Word Wrapping State
  2690. if (m_enableWordWrapping || m_overflowMode == TextOverflowModes.Truncate || m_overflowMode == TextOverflowModes.Ellipsis || m_overflowMode == TextOverflowModes.Linked)
  2691. {
  2692. #if TMP_PROFILE_ON
  2693. Profiler.BeginSample("TMP - Save Word Wrapping State");
  2694. #endif
  2695. if ((isWhiteSpace || charCode == 0x200B || charCode == 0x2D || charCode == 0xAD) && (!m_isNonBreakingSpace || ignoreNonBreakingSpace) && charCode != 0xA0 && charCode != 0x2007 && charCode != 0x2011 && charCode != 0x202F && charCode != 0x2060)
  2696. {
  2697. // We store the state of numerous variables for the most recent Space, LineFeed or Carriage Return to enable them to be restored
  2698. // for Word Wrapping.
  2699. SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
  2700. isFirstWordOfLine = false;
  2701. //isLastCharacterCJK = false;
  2702. // Reset soft line breaking point since we now have a valid hard break point.
  2703. m_SavedSoftLineBreakState.previous_WordBreak = -1;
  2704. }
  2705. // Handling for East Asian characters
  2706. else if (m_isNonBreakingSpace == false &&
  2707. ((charCode > 0x1100 && charCode < 0x11ff || /* Hangul Jamo */
  2708. charCode > 0xA960 && charCode < 0xA97F || /* Hangul Jamo Extended-A */
  2709. charCode > 0xAC00 && charCode < 0xD7FF)&& /* Hangul Syllables */
  2710. TMP_Settings.useModernHangulLineBreakingRules == false ||
  2711. (charCode > 0x2E80 && charCode < 0x9FFF || /* CJK */
  2712. charCode > 0xF900 && charCode < 0xFAFF || /* CJK Compatibility Ideographs */
  2713. charCode > 0xFE30 && charCode < 0xFE4F || /* CJK Compatibility Forms */
  2714. charCode > 0xFF00 && charCode < 0xFFEF))) /* CJK Halfwidth */
  2715. {
  2716. bool isCurrentLeadingCharacter = TMP_Settings.linebreakingRules.leadingCharacters.ContainsKey(charCode);
  2717. bool isNextFollowingCharacter = m_characterCount < totalCharacterCount - 1 && TMP_Settings.linebreakingRules.followingCharacters.ContainsKey(m_textInfo.characterInfo[m_characterCount + 1].character);
  2718. if (isCurrentLeadingCharacter == false)
  2719. {
  2720. if (isNextFollowingCharacter == false)
  2721. {
  2722. SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
  2723. isFirstWordOfLine = false;
  2724. }
  2725. if (isFirstWordOfLine)
  2726. {
  2727. // Special handling for non-breaking space and soft line breaks
  2728. if (isWhiteSpace)
  2729. SaveWordWrappingState(ref m_SavedSoftLineBreakState, i, m_characterCount);
  2730. SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
  2731. }
  2732. }
  2733. else
  2734. {
  2735. if (isFirstWordOfLine && isFirstCharacterOfLine)
  2736. {
  2737. // Special handling for non-breaking space and soft line breaks
  2738. if (isWhiteSpace)
  2739. SaveWordWrappingState(ref m_SavedSoftLineBreakState, i, m_characterCount);
  2740. SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
  2741. }
  2742. }
  2743. //isLastCharacterCJK = true;
  2744. }
  2745. else if (isFirstWordOfLine)
  2746. {
  2747. // Special handling for non-breaking space and soft line breaks
  2748. if (isWhiteSpace || (charCode == 0xAD && isSoftHyphenIgnored == false))
  2749. SaveWordWrappingState(ref m_SavedSoftLineBreakState, i, m_characterCount);
  2750. SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
  2751. //isLastCharacterCJK = false;
  2752. }
  2753. #if TMP_PROFILE_ON
  2754. Profiler.EndSample();
  2755. #endif
  2756. }
  2757. #endregion Save Word Wrapping State
  2758. SaveWordWrappingState(ref m_SavedLastValidState, i, m_characterCount);
  2759. m_characterCount += 1;
  2760. }
  2761. // Check Auto Sizing and increase font size to fill text container.
  2762. #region Check Auto-Sizing (Upper Font Size Bounds)
  2763. fontSizeDelta = m_maxFontSize - m_minFontSize;
  2764. if (/* !m_isCharacterWrappingEnabled && */ m_enableAutoSizing && fontSizeDelta > 0.051f && m_fontSize < m_fontSizeMax && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  2765. {
  2766. // Reset character width adjustment delta
  2767. if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100)
  2768. m_charWidthAdjDelta = 0;
  2769. m_minFontSize = m_fontSize;
  2770. float sizeDelta = Mathf.Max((m_maxFontSize - m_fontSize) / 2, 0.05f);
  2771. m_fontSize += sizeDelta;
  2772. m_fontSize = Mathf.Min((int)(m_fontSize * 20 + 0.5f) / 20f, m_fontSizeMax);
  2773. //Debug.Log("[" + m_AutoSizeIterationCount + "] Increasing Point Size from [" + m_minFontSize.ToString("f3") + "] to [" + m_fontSize.ToString("f3") + "] with delta of [" + sizeDelta.ToString("f3") + "].");
  2774. return;
  2775. }
  2776. #endregion End Auto-sizing Check
  2777. m_IsAutoSizePointSizeSet = true;
  2778. if (m_AutoSizeIterationCount >= m_AutoSizeMaxIterationCount)
  2779. Debug.Log("Auto Size Iteration Count: " + m_AutoSizeIterationCount + ". Final Point Size: " + m_fontSize);
  2780. // If there are no visible characters or only character is End of Text (0x03)... no need to continue
  2781. if (m_characterCount == 0 || (m_characterCount == 1 && charCode == 0x03))
  2782. {
  2783. ClearMesh();
  2784. // Event indicating the text has been regenerated.
  2785. TMPro_EventManager.ON_TEXT_CHANGED(this);
  2786. return;
  2787. }
  2788. #if TMP_PROFILE_ON
  2789. // End Sampling of Phase I
  2790. Profiler.EndSample();
  2791. Profiler.BeginSample("TMP GenerateText() - Phase II");
  2792. #endif
  2793. // *** PHASE II of Text Generation ***
  2794. int last_vert_index = m_materialReferences[m_Underline.materialIndex].referenceCount * 4;
  2795. // Partial clear of the vertices array to mark unused vertices as degenerate.
  2796. m_textInfo.meshInfo[0].Clear(false);
  2797. // Handle Text Alignment
  2798. #region Text Vertical Alignment
  2799. Vector3 anchorOffset = Vector3.zero;
  2800. Vector3[] corners = m_RectTransformCorners; // GetTextContainerLocalCorners();
  2801. // Handle Vertical Text Alignment
  2802. switch (m_VerticalAlignment)
  2803. {
  2804. // Top Vertically
  2805. case VerticalAlignmentOptions.Top:
  2806. if (m_overflowMode != TextOverflowModes.Page)
  2807. anchorOffset = corners[1] + new Vector3(0 + margins.x, 0 - m_maxTextAscender - margins.y, 0);
  2808. else
  2809. anchorOffset = corners[1] + new Vector3(0 + margins.x, 0 - m_textInfo.pageInfo[pageToDisplay].ascender - margins.y, 0);
  2810. break;
  2811. // Middle Vertically
  2812. case VerticalAlignmentOptions.Middle:
  2813. if (m_overflowMode != TextOverflowModes.Page)
  2814. anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_maxTextAscender + margins.y + maxVisibleDescender - margins.w) / 2, 0);
  2815. else
  2816. anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_textInfo.pageInfo[pageToDisplay].ascender + margins.y + m_textInfo.pageInfo[pageToDisplay].descender - margins.w) / 2, 0);
  2817. break;
  2818. // Bottom Vertically
  2819. case VerticalAlignmentOptions.Bottom:
  2820. if (m_overflowMode != TextOverflowModes.Page)
  2821. anchorOffset = corners[0] + new Vector3(0 + margins.x, 0 - maxVisibleDescender + margins.w, 0);
  2822. else
  2823. anchorOffset = corners[0] + new Vector3(0 + margins.x, 0 - m_textInfo.pageInfo[pageToDisplay].descender + margins.w, 0);
  2824. break;
  2825. // Baseline Vertically
  2826. case VerticalAlignmentOptions.Baseline:
  2827. anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0, 0);
  2828. break;
  2829. // Midline Vertically
  2830. case VerticalAlignmentOptions.Geometry:
  2831. anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_meshExtents.max.y + margins.y + m_meshExtents.min.y - margins.w) / 2, 0);
  2832. break;
  2833. // Capline Vertically
  2834. case VerticalAlignmentOptions.Capline:
  2835. anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_maxCapHeight - margins.y - margins.w) / 2, 0);
  2836. break;
  2837. }
  2838. #endregion
  2839. // Initialization for Second Pass
  2840. Vector3 justificationOffset = Vector3.zero;
  2841. Vector3 offset = Vector3.zero;
  2842. int vert_index_X4 = 0;
  2843. int sprite_index_X4 = 0;
  2844. int wordCount = 0;
  2845. int lineCount = 0;
  2846. int lastLine = 0;
  2847. bool isFirstSeperator = false;
  2848. bool isStartOfWord = false;
  2849. int wordFirstChar = 0;
  2850. int wordLastChar = 0;
  2851. // Second Pass : Line Justification, UV Mapping, Character & Line Visibility & more.
  2852. // Variables used to handle Canvas Render Modes and SDF Scaling
  2853. bool isCameraAssigned = m_canvas.worldCamera == null ? false : true;
  2854. float lossyScale = m_previousLossyScaleY = this.transform.lossyScale.y;
  2855. RenderMode canvasRenderMode = m_canvas.renderMode;
  2856. float canvasScaleFactor = m_canvas.scaleFactor;
  2857. Color32 underlineColor = Color.white;
  2858. Color32 strikethroughColor = Color.white;
  2859. HighlightState highlightState = new HighlightState(new Color32(255, 255, 0, 64), TMP_Offset.zero);
  2860. float xScale = 0;
  2861. float xScaleMax = 0;
  2862. float underlineStartScale = 0;
  2863. float underlineEndScale = 0;
  2864. float underlineMaxScale = 0;
  2865. float underlineBaseLine = k_LargePositiveFloat;
  2866. int lastPage = 0;
  2867. float strikethroughPointSize = 0;
  2868. float strikethroughScale = 0;
  2869. float strikethroughBaseline = 0;
  2870. TMP_CharacterInfo[] characterInfos = m_textInfo.characterInfo;
  2871. #region Handle Line Justification & UV Mapping & Character Visibility & More
  2872. for (int i = 0; i < m_characterCount; i++)
  2873. {
  2874. TMP_FontAsset currentFontAsset = characterInfos[i].fontAsset;
  2875. char unicode = characterInfos[i].character;
  2876. int currentLine = characterInfos[i].lineNumber;
  2877. TMP_LineInfo lineInfo = m_textInfo.lineInfo[currentLine];
  2878. lineCount = currentLine + 1;
  2879. HorizontalAlignmentOptions lineAlignment = lineInfo.alignment;
  2880. // Process Line Justification
  2881. #region Handle Line Justification
  2882. switch (lineAlignment)
  2883. {
  2884. case HorizontalAlignmentOptions.Left:
  2885. if (!m_isRightToLeft)
  2886. justificationOffset = new Vector3(0 + lineInfo.marginLeft, 0, 0);
  2887. else
  2888. justificationOffset = new Vector3(0 - lineInfo.maxAdvance, 0, 0);
  2889. break;
  2890. case HorizontalAlignmentOptions.Center:
  2891. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width / 2 - lineInfo.maxAdvance / 2, 0, 0);
  2892. break;
  2893. case HorizontalAlignmentOptions.Geometry:
  2894. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width / 2 - (lineInfo.lineExtents.min.x + lineInfo.lineExtents.max.x) / 2, 0, 0);
  2895. break;
  2896. case HorizontalAlignmentOptions.Right:
  2897. if (!m_isRightToLeft)
  2898. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width - lineInfo.maxAdvance, 0, 0);
  2899. else
  2900. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width, 0, 0);
  2901. break;
  2902. case HorizontalAlignmentOptions.Justified:
  2903. case HorizontalAlignmentOptions.Flush:
  2904. // Skip Zero Width Characters
  2905. if (unicode == 0x0A || unicode == 0xAD || unicode == 0x200B || unicode == 0x2060 || unicode == 0x03) break;
  2906. char lastCharOfCurrentLine = characterInfos[lineInfo.lastCharacterIndex].character;
  2907. bool isFlush = (lineAlignment & HorizontalAlignmentOptions.Flush) == HorizontalAlignmentOptions.Flush;
  2908. // In Justified mode, all lines are justified except the last one.
  2909. // In Flush mode, all lines are justified.
  2910. if (char.IsControl(lastCharOfCurrentLine) == false && currentLine < m_lineNumber || isFlush || lineInfo.maxAdvance > lineInfo.width)
  2911. {
  2912. // First character of each line.
  2913. if (currentLine != lastLine || i == 0 /*|| i == lineInfo.firstVisibleCharacterIndex */ || i == m_firstVisibleCharacter)
  2914. {
  2915. if (!m_isRightToLeft)
  2916. justificationOffset = new Vector3(lineInfo.marginLeft, 0, 0);
  2917. else
  2918. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width, 0, 0);
  2919. if (char.IsSeparator(unicode))
  2920. isFirstSeperator = true;
  2921. else
  2922. isFirstSeperator = false;
  2923. }
  2924. else
  2925. {
  2926. float gap = !m_isRightToLeft ? lineInfo.width - lineInfo.maxAdvance : lineInfo.width + lineInfo.maxAdvance;
  2927. int visibleCount = lineInfo.visibleCharacterCount - 1 + lineInfo.controlCharacterCount;
  2928. // Get the number of spaces for each line ignoring the last character if it is not visible (ie. a space or linefeed).
  2929. int spaces = (characterInfos[lineInfo.lastCharacterIndex].isVisible ? lineInfo.spaceCount : lineInfo.spaceCount - 1) - lineInfo.controlCharacterCount;
  2930. if (isFirstSeperator) { spaces -= 1; visibleCount += 1; }
  2931. float ratio = spaces > 0 ? m_wordWrappingRatios : 1;
  2932. if (spaces < 1) spaces = 1;
  2933. if (unicode != 0xA0 && (unicode == 9 || char.IsSeparator((char)unicode)))
  2934. {
  2935. if (!m_isRightToLeft)
  2936. justificationOffset += new Vector3(gap * (1 - ratio) / spaces, 0, 0);
  2937. else
  2938. justificationOffset -= new Vector3(gap * (1 - ratio) / spaces, 0, 0);
  2939. }
  2940. else
  2941. {
  2942. if (!m_isRightToLeft)
  2943. justificationOffset += new Vector3(gap * ratio / visibleCount, 0, 0);
  2944. else
  2945. justificationOffset -= new Vector3(gap * ratio / visibleCount, 0, 0);
  2946. }
  2947. }
  2948. }
  2949. else
  2950. {
  2951. if (!m_isRightToLeft)
  2952. justificationOffset = new Vector3(lineInfo.marginLeft, 0, 0); // Keep last line left justified.
  2953. else
  2954. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width, 0, 0); // Keep last line right justified.
  2955. }
  2956. //Debug.Log("Char [" + (char)charCode + "] Code:" + charCode + " Line # " + currentLine + " Offset:" + justificationOffset + " # Spaces:" + lineInfo.spaceCount + " # Characters:" + lineInfo.characterCount);
  2957. break;
  2958. }
  2959. #endregion End Text Justification
  2960. offset = anchorOffset + justificationOffset;
  2961. // Handle UV2 mapping options and packing of scale information into UV2.
  2962. #region Handling of UV2 mapping & Scale packing
  2963. bool isCharacterVisible = characterInfos[i].isVisible;
  2964. if (isCharacterVisible)
  2965. {
  2966. TMP_TextElementType elementType = characterInfos[i].elementType;
  2967. switch (elementType)
  2968. {
  2969. // CHARACTERS
  2970. case TMP_TextElementType.Character:
  2971. Extents lineExtents = lineInfo.lineExtents;
  2972. float uvOffset = (m_uvLineOffset * currentLine) % 1; // + m_uvOffset.x;
  2973. // Setup UV2 based on Character Mapping Options Selected
  2974. #region Handle UV Mapping Options
  2975. switch (m_horizontalMapping)
  2976. {
  2977. case TextureMappingOptions.Character:
  2978. characterInfos[i].vertex_BL.uv2.x = 0; //+ m_uvOffset.x;
  2979. characterInfos[i].vertex_TL.uv2.x = 0; //+ m_uvOffset.x;
  2980. characterInfos[i].vertex_TR.uv2.x = 1; //+ m_uvOffset.x;
  2981. characterInfos[i].vertex_BR.uv2.x = 1; //+ m_uvOffset.x;
  2982. break;
  2983. case TextureMappingOptions.Line:
  2984. if (m_textAlignment != TextAlignmentOptions.Justified)
  2985. {
  2986. characterInfos[i].vertex_BL.uv2.x = (characterInfos[i].vertex_BL.position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
  2987. characterInfos[i].vertex_TL.uv2.x = (characterInfos[i].vertex_TL.position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
  2988. characterInfos[i].vertex_TR.uv2.x = (characterInfos[i].vertex_TR.position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
  2989. characterInfos[i].vertex_BR.uv2.x = (characterInfos[i].vertex_BR.position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
  2990. break;
  2991. }
  2992. else // Special Case if Justified is used in Line Mode.
  2993. {
  2994. characterInfos[i].vertex_BL.uv2.x = (characterInfos[i].vertex_BL.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  2995. characterInfos[i].vertex_TL.uv2.x = (characterInfos[i].vertex_TL.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  2996. characterInfos[i].vertex_TR.uv2.x = (characterInfos[i].vertex_TR.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  2997. characterInfos[i].vertex_BR.uv2.x = (characterInfos[i].vertex_BR.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  2998. break;
  2999. }
  3000. case TextureMappingOptions.Paragraph:
  3001. characterInfos[i].vertex_BL.uv2.x = (characterInfos[i].vertex_BL.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  3002. characterInfos[i].vertex_TL.uv2.x = (characterInfos[i].vertex_TL.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  3003. characterInfos[i].vertex_TR.uv2.x = (characterInfos[i].vertex_TR.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  3004. characterInfos[i].vertex_BR.uv2.x = (characterInfos[i].vertex_BR.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  3005. break;
  3006. case TextureMappingOptions.MatchAspect:
  3007. switch (m_verticalMapping)
  3008. {
  3009. case TextureMappingOptions.Character:
  3010. characterInfos[i].vertex_BL.uv2.y = 0; // + m_uvOffset.y;
  3011. characterInfos[i].vertex_TL.uv2.y = 1; // + m_uvOffset.y;
  3012. characterInfos[i].vertex_TR.uv2.y = 0; // + m_uvOffset.y;
  3013. characterInfos[i].vertex_BR.uv2.y = 1; // + m_uvOffset.y;
  3014. break;
  3015. case TextureMappingOptions.Line:
  3016. characterInfos[i].vertex_BL.uv2.y = (characterInfos[i].vertex_BL.position.y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + uvOffset;
  3017. characterInfos[i].vertex_TL.uv2.y = (characterInfos[i].vertex_TL.position.y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + uvOffset;
  3018. characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
  3019. characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
  3020. break;
  3021. case TextureMappingOptions.Paragraph:
  3022. characterInfos[i].vertex_BL.uv2.y = (characterInfos[i].vertex_BL.position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + uvOffset;
  3023. characterInfos[i].vertex_TL.uv2.y = (characterInfos[i].vertex_TL.position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + uvOffset;
  3024. characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
  3025. characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
  3026. break;
  3027. case TextureMappingOptions.MatchAspect:
  3028. Debug.Log("ERROR: Cannot Match both Vertical & Horizontal.");
  3029. break;
  3030. }
  3031. //float xDelta = 1 - (_uv2s[vert_index + 0].y * textMeshCharacterInfo[i].AspectRatio); // Left aligned
  3032. float xDelta = (1 - ((characterInfos[i].vertex_BL.uv2.y + characterInfos[i].vertex_TL.uv2.y) * characterInfos[i].aspectRatio)) / 2; // Center of Rectangle
  3033. characterInfos[i].vertex_BL.uv2.x = (characterInfos[i].vertex_BL.uv2.y * characterInfos[i].aspectRatio) + xDelta + uvOffset;
  3034. characterInfos[i].vertex_TL.uv2.x = characterInfos[i].vertex_BL.uv2.x;
  3035. characterInfos[i].vertex_TR.uv2.x = (characterInfos[i].vertex_TL.uv2.y * characterInfos[i].aspectRatio) + xDelta + uvOffset;
  3036. characterInfos[i].vertex_BR.uv2.x = characterInfos[i].vertex_TR.uv2.x;
  3037. break;
  3038. }
  3039. switch (m_verticalMapping)
  3040. {
  3041. case TextureMappingOptions.Character:
  3042. characterInfos[i].vertex_BL.uv2.y = 0; // + m_uvOffset.y;
  3043. characterInfos[i].vertex_TL.uv2.y = 1; // + m_uvOffset.y;
  3044. characterInfos[i].vertex_TR.uv2.y = 1; // + m_uvOffset.y;
  3045. characterInfos[i].vertex_BR.uv2.y = 0; // + m_uvOffset.y;
  3046. break;
  3047. case TextureMappingOptions.Line:
  3048. characterInfos[i].vertex_BL.uv2.y = (characterInfos[i].vertex_BL.position.y - lineInfo.descender) / (lineInfo.ascender - lineInfo.descender); // + m_uvOffset.y;
  3049. characterInfos[i].vertex_TL.uv2.y = (characterInfos[i].vertex_TL.position.y - lineInfo.descender) / (lineInfo.ascender - lineInfo.descender); // + m_uvOffset.y;
  3050. characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
  3051. characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
  3052. break;
  3053. case TextureMappingOptions.Paragraph:
  3054. characterInfos[i].vertex_BL.uv2.y = (characterInfos[i].vertex_BL.position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y); // + m_uvOffset.y;
  3055. characterInfos[i].vertex_TL.uv2.y = (characterInfos[i].vertex_TL.position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y); // + m_uvOffset.y;
  3056. characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
  3057. characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
  3058. break;
  3059. case TextureMappingOptions.MatchAspect:
  3060. float yDelta = (1 - ((characterInfos[i].vertex_BL.uv2.x + characterInfos[i].vertex_TR.uv2.x) / characterInfos[i].aspectRatio)) / 2; // Center of Rectangle
  3061. characterInfos[i].vertex_BL.uv2.y = yDelta + (characterInfos[i].vertex_BL.uv2.x / characterInfos[i].aspectRatio); // + m_uvOffset.y;
  3062. characterInfos[i].vertex_TL.uv2.y = yDelta + (characterInfos[i].vertex_TR.uv2.x / characterInfos[i].aspectRatio); // + m_uvOffset.y;
  3063. characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
  3064. characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
  3065. break;
  3066. }
  3067. #endregion
  3068. // Pack UV's so that we can pass Xscale needed for Shader to maintain 1:1 ratio.
  3069. #region Pack Scale into UV2
  3070. xScale = characterInfos[i].scale * (1 - m_charWidthAdjDelta);
  3071. if (!characterInfos[i].isUsingAlternateTypeface && (characterInfos[i].style & FontStyles.Bold) == FontStyles.Bold) xScale *= -1;
  3072. switch (canvasRenderMode)
  3073. {
  3074. case RenderMode.ScreenSpaceOverlay:
  3075. xScale *= Mathf.Abs(lossyScale) / canvasScaleFactor;
  3076. break;
  3077. case RenderMode.ScreenSpaceCamera:
  3078. xScale *= isCameraAssigned ? Mathf.Abs(lossyScale) : 1;
  3079. break;
  3080. case RenderMode.WorldSpace:
  3081. xScale *= Mathf.Abs(lossyScale);
  3082. break;
  3083. }
  3084. // isBold is encoded in the X value and SDF Scale in Y.
  3085. //Vector2 vertexData = new Vector2((characterInfos[i].style & FontStyles.Bold) == FontStyles.Bold ? 1 : 0, xScale);
  3086. //characterInfos[i].vertex_BL.uv2 = vertexData;
  3087. //characterInfos[i].vertex_TL.uv2 = vertexData;
  3088. //characterInfos[i].vertex_TR.uv2 = vertexData;
  3089. //characterInfos[i].vertex_BR.uv2 = vertexData;
  3090. float x0 = characterInfos[i].vertex_BL.uv2.x;
  3091. float y0 = characterInfos[i].vertex_BL.uv2.y;
  3092. float x1 = characterInfos[i].vertex_TR.uv2.x;
  3093. float y1 = characterInfos[i].vertex_TR.uv2.y;
  3094. float dx = (int)x0;
  3095. float dy = (int)y0;
  3096. x0 = x0 - dx;
  3097. x1 = x1 - dx;
  3098. y0 = y0 - dy;
  3099. y1 = y1 - dy;
  3100. // Optimization to avoid having a vector2 returned from the Pack UV function.
  3101. characterInfos[i].vertex_BL.uv2.x = PackUV(x0, y0); characterInfos[i].vertex_BL.uv2.y = xScale;
  3102. characterInfos[i].vertex_TL.uv2.x = PackUV(x0, y1); characterInfos[i].vertex_TL.uv2.y = xScale;
  3103. characterInfos[i].vertex_TR.uv2.x = PackUV(x1, y1); characterInfos[i].vertex_TR.uv2.y = xScale;
  3104. characterInfos[i].vertex_BR.uv2.x = PackUV(x1, y0); characterInfos[i].vertex_BR.uv2.y = xScale;
  3105. #endregion
  3106. break;
  3107. // SPRITES
  3108. case TMP_TextElementType.Sprite:
  3109. // Nothing right now
  3110. break;
  3111. }
  3112. // Handle maxVisibleCharacters, maxVisibleLines and Overflow Page Mode.
  3113. #region Handle maxVisibleCharacters / maxVisibleLines / Page Mode
  3114. if (i < m_maxVisibleCharacters && wordCount < m_maxVisibleWords && currentLine < m_maxVisibleLines && m_overflowMode != TextOverflowModes.Page)
  3115. {
  3116. characterInfos[i].vertex_BL.position += offset;
  3117. characterInfos[i].vertex_TL.position += offset;
  3118. characterInfos[i].vertex_TR.position += offset;
  3119. characterInfos[i].vertex_BR.position += offset;
  3120. }
  3121. else if (i < m_maxVisibleCharacters && wordCount < m_maxVisibleWords && currentLine < m_maxVisibleLines && m_overflowMode == TextOverflowModes.Page && characterInfos[i].pageNumber == pageToDisplay)
  3122. {
  3123. characterInfos[i].vertex_BL.position += offset;
  3124. characterInfos[i].vertex_TL.position += offset;
  3125. characterInfos[i].vertex_TR.position += offset;
  3126. characterInfos[i].vertex_BR.position += offset;
  3127. }
  3128. else
  3129. {
  3130. characterInfos[i].vertex_BL.position = Vector3.zero;
  3131. characterInfos[i].vertex_TL.position = Vector3.zero;
  3132. characterInfos[i].vertex_TR.position = Vector3.zero;
  3133. characterInfos[i].vertex_BR.position = Vector3.zero;
  3134. characterInfos[i].isVisible = false;
  3135. }
  3136. #endregion
  3137. // Fill Vertex Buffers for the various types of element
  3138. if (elementType == TMP_TextElementType.Character)
  3139. {
  3140. FillCharacterVertexBuffers(i, vert_index_X4);
  3141. }
  3142. else if (elementType == TMP_TextElementType.Sprite)
  3143. {
  3144. FillSpriteVertexBuffers(i, sprite_index_X4);
  3145. }
  3146. }
  3147. #endregion
  3148. // Apply Alignment and Justification Offset
  3149. m_textInfo.characterInfo[i].bottomLeft += offset;
  3150. m_textInfo.characterInfo[i].topLeft += offset;
  3151. m_textInfo.characterInfo[i].topRight += offset;
  3152. m_textInfo.characterInfo[i].bottomRight += offset;
  3153. m_textInfo.characterInfo[i].origin += offset.x;
  3154. m_textInfo.characterInfo[i].xAdvance += offset.x;
  3155. m_textInfo.characterInfo[i].ascender += offset.y;
  3156. m_textInfo.characterInfo[i].descender += offset.y;
  3157. m_textInfo.characterInfo[i].baseLine += offset.y;
  3158. // Update MeshExtents
  3159. if (isCharacterVisible)
  3160. {
  3161. //m_meshExtents.min = new Vector2(Mathf.Min(m_meshExtents.min.x, m_textInfo.characterInfo[i].bottomLeft.x), Mathf.Min(m_meshExtents.min.y, m_textInfo.characterInfo[i].bottomLeft.y));
  3162. //m_meshExtents.max = new Vector2(Mathf.Max(m_meshExtents.max.x, m_textInfo.characterInfo[i].topRight.x), Mathf.Max(m_meshExtents.max.y, m_textInfo.characterInfo[i].topLeft.y));
  3163. }
  3164. // Need to recompute lineExtent to account for the offset from justification.
  3165. #region Adjust lineExtents resulting from alignment offset
  3166. if (currentLine != lastLine || i == m_characterCount - 1)
  3167. {
  3168. // Update the previous line's extents
  3169. if (currentLine != lastLine)
  3170. {
  3171. m_textInfo.lineInfo[lastLine].baseline += offset.y;
  3172. m_textInfo.lineInfo[lastLine].ascender += offset.y;
  3173. m_textInfo.lineInfo[lastLine].descender += offset.y;
  3174. m_textInfo.lineInfo[lastLine].maxAdvance += offset.x;
  3175. m_textInfo.lineInfo[lastLine].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[lastLine].firstCharacterIndex].bottomLeft.x, m_textInfo.lineInfo[lastLine].descender);
  3176. m_textInfo.lineInfo[lastLine].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[lastLine].lastVisibleCharacterIndex].topRight.x, m_textInfo.lineInfo[lastLine].ascender);
  3177. }
  3178. // Update the current line's extents
  3179. if (i == m_characterCount - 1)
  3180. {
  3181. m_textInfo.lineInfo[currentLine].baseline += offset.y;
  3182. m_textInfo.lineInfo[currentLine].ascender += offset.y;
  3183. m_textInfo.lineInfo[currentLine].descender += offset.y;
  3184. m_textInfo.lineInfo[currentLine].maxAdvance += offset.x;
  3185. m_textInfo.lineInfo[currentLine].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[currentLine].firstCharacterIndex].bottomLeft.x, m_textInfo.lineInfo[currentLine].descender);
  3186. m_textInfo.lineInfo[currentLine].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[currentLine].lastVisibleCharacterIndex].topRight.x, m_textInfo.lineInfo[currentLine].ascender);
  3187. }
  3188. }
  3189. #endregion
  3190. // Track Word Count per line and for the object
  3191. #region Track Word Count
  3192. if (char.IsLetterOrDigit(unicode) || unicode == 0x2D || unicode == 0xAD || unicode == 0x2010 || unicode == 0x2011)
  3193. {
  3194. if (isStartOfWord == false)
  3195. {
  3196. isStartOfWord = true;
  3197. wordFirstChar = i;
  3198. }
  3199. // If last character is a word
  3200. if (isStartOfWord && i == m_characterCount - 1)
  3201. {
  3202. int size = m_textInfo.wordInfo.Length;
  3203. int index = m_textInfo.wordCount;
  3204. if (m_textInfo.wordCount + 1 > size)
  3205. TMP_TextInfo.Resize(ref m_textInfo.wordInfo, size + 1);
  3206. wordLastChar = i;
  3207. m_textInfo.wordInfo[index].firstCharacterIndex = wordFirstChar;
  3208. m_textInfo.wordInfo[index].lastCharacterIndex = wordLastChar;
  3209. m_textInfo.wordInfo[index].characterCount = wordLastChar - wordFirstChar + 1;
  3210. m_textInfo.wordInfo[index].textComponent = this;
  3211. wordCount += 1;
  3212. m_textInfo.wordCount += 1;
  3213. m_textInfo.lineInfo[currentLine].wordCount += 1;
  3214. }
  3215. }
  3216. else if (isStartOfWord || i == 0 && (!char.IsPunctuation(unicode) || char.IsWhiteSpace(unicode) || unicode == 0x200B || i == m_characterCount - 1))
  3217. {
  3218. if (i > 0 && i < characterInfos.Length - 1 && i < m_characterCount && (unicode == 39 || unicode == 8217) && char.IsLetterOrDigit(characterInfos[i - 1].character) && char.IsLetterOrDigit(characterInfos[i + 1].character))
  3219. {
  3220. }
  3221. else
  3222. {
  3223. wordLastChar = i == m_characterCount - 1 && char.IsLetterOrDigit(unicode) ? i : i - 1;
  3224. isStartOfWord = false;
  3225. int size = m_textInfo.wordInfo.Length;
  3226. int index = m_textInfo.wordCount;
  3227. if (m_textInfo.wordCount + 1 > size)
  3228. TMP_TextInfo.Resize(ref m_textInfo.wordInfo, size + 1);
  3229. m_textInfo.wordInfo[index].firstCharacterIndex = wordFirstChar;
  3230. m_textInfo.wordInfo[index].lastCharacterIndex = wordLastChar;
  3231. m_textInfo.wordInfo[index].characterCount = wordLastChar - wordFirstChar + 1;
  3232. m_textInfo.wordInfo[index].textComponent = this;
  3233. wordCount += 1;
  3234. m_textInfo.wordCount += 1;
  3235. m_textInfo.lineInfo[currentLine].wordCount += 1;
  3236. }
  3237. }
  3238. #endregion
  3239. // Setup & Handle Underline
  3240. #region Underline
  3241. // NOTE: Need to figure out how underline will be handled with multiple fonts and which font will be used for the underline.
  3242. bool isUnderline = (m_textInfo.characterInfo[i].style & FontStyles.Underline) == FontStyles.Underline;
  3243. if (isUnderline)
  3244. {
  3245. bool isUnderlineVisible = true;
  3246. int currentPage = m_textInfo.characterInfo[i].pageNumber;
  3247. m_textInfo.characterInfo[i].underlineVertexIndex = last_vert_index;
  3248. if (i > m_maxVisibleCharacters || currentLine > m_maxVisibleLines || (m_overflowMode == TextOverflowModes.Page && currentPage + 1 != m_pageToDisplay))
  3249. isUnderlineVisible = false;
  3250. // We only use the scale of visible characters.
  3251. if (!char.IsWhiteSpace(unicode) && unicode != 0x200B)
  3252. {
  3253. underlineMaxScale = Mathf.Max(underlineMaxScale, m_textInfo.characterInfo[i].scale);
  3254. xScaleMax = Mathf.Max(xScaleMax, Mathf.Abs(xScale));
  3255. underlineBaseLine = Mathf.Min(currentPage == lastPage ? underlineBaseLine : k_LargePositiveFloat, m_textInfo.characterInfo[i].baseLine + font.m_FaceInfo.underlineOffset * underlineMaxScale);
  3256. lastPage = currentPage; // Need to track pages to ensure we reset baseline for the new pages.
  3257. }
  3258. if (beginUnderline == false && isUnderlineVisible == true && i <= lineInfo.lastVisibleCharacterIndex && unicode != 10 && unicode != 11 && unicode != 13)
  3259. {
  3260. if (i == lineInfo.lastVisibleCharacterIndex && char.IsSeparator(unicode))
  3261. { }
  3262. else
  3263. {
  3264. beginUnderline = true;
  3265. underlineStartScale = m_textInfo.characterInfo[i].scale;
  3266. if (underlineMaxScale == 0)
  3267. {
  3268. underlineMaxScale = underlineStartScale;
  3269. xScaleMax = xScale;
  3270. }
  3271. underline_start = new Vector3(m_textInfo.characterInfo[i].bottomLeft.x, underlineBaseLine, 0);
  3272. underlineColor = m_textInfo.characterInfo[i].underlineColor;
  3273. }
  3274. }
  3275. // End Underline if text only contains one character.
  3276. if (beginUnderline && m_characterCount == 1)
  3277. {
  3278. beginUnderline = false;
  3279. underline_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, underlineBaseLine, 0);
  3280. underlineEndScale = m_textInfo.characterInfo[i].scale;
  3281. DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, xScaleMax, underlineColor);
  3282. underlineMaxScale = 0;
  3283. xScaleMax = 0;
  3284. underlineBaseLine = k_LargePositiveFloat;
  3285. }
  3286. else if (beginUnderline && (i == lineInfo.lastCharacterIndex || i >= lineInfo.lastVisibleCharacterIndex))
  3287. {
  3288. // Terminate underline at previous visible character if space or carriage return.
  3289. if (char.IsWhiteSpace(unicode) || unicode == 0x200B)
  3290. {
  3291. int lastVisibleCharacterIndex = lineInfo.lastVisibleCharacterIndex;
  3292. underline_end = new Vector3(m_textInfo.characterInfo[lastVisibleCharacterIndex].topRight.x, underlineBaseLine, 0);
  3293. underlineEndScale = m_textInfo.characterInfo[lastVisibleCharacterIndex].scale;
  3294. }
  3295. else
  3296. { // End underline if last character of the line.
  3297. underline_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, underlineBaseLine, 0);
  3298. underlineEndScale = m_textInfo.characterInfo[i].scale;
  3299. }
  3300. beginUnderline = false;
  3301. DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, xScaleMax, underlineColor);
  3302. underlineMaxScale = 0;
  3303. xScaleMax = 0;
  3304. underlineBaseLine = k_LargePositiveFloat;
  3305. }
  3306. else if (beginUnderline && !isUnderlineVisible)
  3307. {
  3308. beginUnderline = false;
  3309. underline_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, underlineBaseLine, 0);
  3310. underlineEndScale = m_textInfo.characterInfo[i - 1].scale;
  3311. DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, xScaleMax, underlineColor);
  3312. underlineMaxScale = 0;
  3313. xScaleMax = 0;
  3314. underlineBaseLine = k_LargePositiveFloat;
  3315. }
  3316. else if (beginUnderline && i < m_characterCount - 1 && !underlineColor.Compare(m_textInfo.characterInfo[i + 1].underlineColor))
  3317. {
  3318. // End underline if underline color has changed.
  3319. beginUnderline = false;
  3320. underline_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, underlineBaseLine, 0);
  3321. underlineEndScale = m_textInfo.characterInfo[i].scale;
  3322. DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, xScaleMax, underlineColor);
  3323. underlineMaxScale = 0;
  3324. xScaleMax = 0;
  3325. underlineBaseLine = k_LargePositiveFloat;
  3326. }
  3327. }
  3328. else
  3329. {
  3330. // End Underline
  3331. if (beginUnderline == true)
  3332. {
  3333. beginUnderline = false;
  3334. underline_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, underlineBaseLine, 0);
  3335. underlineEndScale = m_textInfo.characterInfo[i - 1].scale;
  3336. DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, xScaleMax, underlineColor);
  3337. underlineMaxScale = 0;
  3338. xScaleMax = 0;
  3339. underlineBaseLine = k_LargePositiveFloat;
  3340. }
  3341. }
  3342. #endregion
  3343. // Setup & Handle Strikethrough
  3344. #region Strikethrough
  3345. // NOTE: Need to figure out how underline will be handled with multiple fonts and which font will be used for the underline.
  3346. bool isStrikethrough = (m_textInfo.characterInfo[i].style & FontStyles.Strikethrough) == FontStyles.Strikethrough;
  3347. float strikethroughOffset = currentFontAsset.m_FaceInfo.strikethroughOffset;
  3348. if (isStrikethrough)
  3349. {
  3350. bool isStrikeThroughVisible = true;
  3351. m_textInfo.characterInfo[i].strikethroughVertexIndex = last_vert_index;
  3352. if (i > m_maxVisibleCharacters || currentLine > m_maxVisibleLines || (m_overflowMode == TextOverflowModes.Page && m_textInfo.characterInfo[i].pageNumber + 1 != m_pageToDisplay))
  3353. isStrikeThroughVisible = false;
  3354. if (beginStrikethrough == false && isStrikeThroughVisible && i <= lineInfo.lastVisibleCharacterIndex && unicode != 10 && unicode != 11 && unicode != 13)
  3355. {
  3356. if (i == lineInfo.lastVisibleCharacterIndex && char.IsSeparator(unicode))
  3357. { }
  3358. else
  3359. {
  3360. beginStrikethrough = true;
  3361. strikethroughPointSize = m_textInfo.characterInfo[i].pointSize;
  3362. strikethroughScale = m_textInfo.characterInfo[i].scale;
  3363. strikethrough_start = new Vector3(m_textInfo.characterInfo[i].bottomLeft.x, m_textInfo.characterInfo[i].baseLine + strikethroughOffset * strikethroughScale, 0);
  3364. strikethroughColor = m_textInfo.characterInfo[i].strikethroughColor;
  3365. strikethroughBaseline = m_textInfo.characterInfo[i].baseLine;
  3366. //Debug.Log("Char [" + currentCharacter + "] Start Strikethrough POS: " + strikethrough_start);
  3367. }
  3368. }
  3369. // End Strikethrough if text only contains one character.
  3370. if (beginStrikethrough && m_characterCount == 1)
  3371. {
  3372. beginStrikethrough = false;
  3373. strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + strikethroughOffset * strikethroughScale, 0);
  3374. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  3375. }
  3376. else if (beginStrikethrough && i == lineInfo.lastCharacterIndex)
  3377. {
  3378. // Terminate Strikethrough at previous visible character if space or carriage return.
  3379. if (char.IsWhiteSpace(unicode) || unicode == 0x200B)
  3380. {
  3381. int lastVisibleCharacterIndex = lineInfo.lastVisibleCharacterIndex;
  3382. strikethrough_end = new Vector3(m_textInfo.characterInfo[lastVisibleCharacterIndex].topRight.x, m_textInfo.characterInfo[lastVisibleCharacterIndex].baseLine + strikethroughOffset * strikethroughScale, 0);
  3383. }
  3384. else
  3385. {
  3386. // Terminate Strikethrough at last character of line.
  3387. strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + strikethroughOffset * strikethroughScale, 0);
  3388. }
  3389. beginStrikethrough = false;
  3390. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  3391. }
  3392. else if (beginStrikethrough && i < m_characterCount && (m_textInfo.characterInfo[i + 1].pointSize != strikethroughPointSize || !TMP_Math.Approximately(m_textInfo.characterInfo[i + 1].baseLine + offset.y, strikethroughBaseline)))
  3393. {
  3394. // Terminate Strikethrough if scale changes.
  3395. beginStrikethrough = false;
  3396. int lastVisibleCharacterIndex = lineInfo.lastVisibleCharacterIndex;
  3397. if (i > lastVisibleCharacterIndex)
  3398. strikethrough_end = new Vector3(m_textInfo.characterInfo[lastVisibleCharacterIndex].topRight.x, m_textInfo.characterInfo[lastVisibleCharacterIndex].baseLine + strikethroughOffset * strikethroughScale, 0);
  3399. else
  3400. strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + strikethroughOffset * strikethroughScale, 0);
  3401. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  3402. //Debug.Log("Char [" + currentCharacter + "] at Index: " + i + " End Strikethrough POS: " + strikethrough_end + " Baseline: " + m_textInfo.characterInfo[i].baseLine.ToString("f3"));
  3403. }
  3404. else if (beginStrikethrough && i < m_characterCount && currentFontAsset.GetInstanceID() != characterInfos[i + 1].fontAsset.GetInstanceID())
  3405. {
  3406. // Terminate Strikethrough if font asset changes.
  3407. beginStrikethrough = false;
  3408. strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + strikethroughOffset * strikethroughScale, 0);
  3409. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  3410. }
  3411. else if (beginStrikethrough && !isStrikeThroughVisible)
  3412. {
  3413. // Terminate Strikethrough if character is not visible.
  3414. beginStrikethrough = false;
  3415. strikethrough_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, m_textInfo.characterInfo[i - 1].baseLine + strikethroughOffset * strikethroughScale, 0);
  3416. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  3417. }
  3418. }
  3419. else
  3420. {
  3421. // End Strikethrough
  3422. if (beginStrikethrough == true)
  3423. {
  3424. beginStrikethrough = false;
  3425. strikethrough_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, m_textInfo.characterInfo[i - 1].baseLine + strikethroughOffset * strikethroughScale, 0);
  3426. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  3427. }
  3428. }
  3429. #endregion
  3430. // HANDLE TEXT HIGHLIGHTING
  3431. #region Text Highlighting
  3432. bool isHighlight = (m_textInfo.characterInfo[i].style & FontStyles.Highlight) == FontStyles.Highlight;
  3433. if (isHighlight)
  3434. {
  3435. bool isHighlightVisible = true;
  3436. int currentPage = m_textInfo.characterInfo[i].pageNumber;
  3437. if (i > m_maxVisibleCharacters || currentLine > m_maxVisibleLines || (m_overflowMode == TextOverflowModes.Page && currentPage + 1 != m_pageToDisplay))
  3438. isHighlightVisible = false;
  3439. if (beginHighlight == false && isHighlightVisible == true && i <= lineInfo.lastVisibleCharacterIndex && unicode != 10 && unicode != 11 && unicode != 13)
  3440. {
  3441. if (i == lineInfo.lastVisibleCharacterIndex && char.IsSeparator(unicode))
  3442. { }
  3443. else
  3444. {
  3445. beginHighlight = true;
  3446. highlight_start = k_LargePositiveVector2;
  3447. highlight_end = k_LargeNegativeVector2;
  3448. highlightState = m_textInfo.characterInfo[i].highlightState;
  3449. }
  3450. }
  3451. if (beginHighlight)
  3452. {
  3453. TMP_CharacterInfo currentCharacter = m_textInfo.characterInfo[i];
  3454. HighlightState currentState = currentCharacter.highlightState;
  3455. bool isColorTransition = false;
  3456. // Handle Highlight color changes
  3457. if (highlightState != currentCharacter.highlightState)
  3458. {
  3459. // Adjust previous highlight section to prevent a gaps between sections.
  3460. highlight_end.x = (highlight_end.x - highlightState.padding.right + currentCharacter.bottomLeft.x) / 2;
  3461. highlight_start.y = Mathf.Min(highlight_start.y, currentCharacter.descender);
  3462. highlight_end.y = Mathf.Max(highlight_end.y, currentCharacter.ascender);
  3463. DrawTextHighlight(highlight_start, highlight_end, ref last_vert_index, highlightState.color);
  3464. beginHighlight = true;
  3465. highlight_start = new Vector2(highlight_end.x, currentCharacter.descender - currentState.padding.bottom);
  3466. highlight_end = new Vector2(currentCharacter.topRight.x + currentState.padding.right, currentCharacter.ascender + currentState.padding.top);
  3467. highlightState = currentCharacter.highlightState;
  3468. isColorTransition = true;
  3469. }
  3470. if (!isColorTransition)
  3471. {
  3472. // Use the Min / Max Extents of the Highlight area to handle different character sizes and fonts.
  3473. highlight_start.x = Mathf.Min(highlight_start.x, currentCharacter.bottomLeft.x - highlightState.padding.left);
  3474. highlight_start.y = Mathf.Min(highlight_start.y, currentCharacter.descender - highlightState.padding.bottom);
  3475. highlight_end.x = Mathf.Max(highlight_end.x, currentCharacter.topRight.x + highlightState.padding.right);
  3476. highlight_end.y = Mathf.Max(highlight_end.y, currentCharacter.ascender + highlightState.padding.top);
  3477. }
  3478. }
  3479. // End Highlight if text only contains one character.
  3480. if (beginHighlight && m_characterCount == 1)
  3481. {
  3482. beginHighlight = false;
  3483. DrawTextHighlight(highlight_start, highlight_end, ref last_vert_index, highlightState.color);
  3484. }
  3485. else if (beginHighlight && (i == lineInfo.lastCharacterIndex || i >= lineInfo.lastVisibleCharacterIndex))
  3486. {
  3487. beginHighlight = false;
  3488. DrawTextHighlight(highlight_start, highlight_end, ref last_vert_index, highlightState.color);
  3489. }
  3490. else if (beginHighlight && !isHighlightVisible)
  3491. {
  3492. beginHighlight = false;
  3493. DrawTextHighlight(highlight_start, highlight_end, ref last_vert_index, highlightState.color);
  3494. }
  3495. }
  3496. else
  3497. {
  3498. // End Highlight
  3499. if (beginHighlight == true)
  3500. {
  3501. beginHighlight = false;
  3502. DrawTextHighlight(highlight_start, highlight_end, ref last_vert_index, highlightState.color);
  3503. }
  3504. }
  3505. #endregion
  3506. lastLine = currentLine;
  3507. }
  3508. #endregion
  3509. // METRICS ABOUT THE TEXT OBJECT
  3510. m_textInfo.characterCount = m_characterCount;
  3511. m_textInfo.spriteCount = m_spriteCount;
  3512. m_textInfo.lineCount = lineCount;
  3513. m_textInfo.wordCount = wordCount != 0 && m_characterCount > 0 ? wordCount : 1;
  3514. m_textInfo.pageCount = m_pageNumber + 1;
  3515. // Set vertex count for Underline geometry
  3516. //m_textInfo.meshInfo[m_Underline.materialIndex].vertexCount = last_vert_index;
  3517. #if TMP_PROFILE_ON
  3518. // End Sampling of Phase II
  3519. Profiler.EndSample();
  3520. Profiler.BeginSample("TMP GenerateText() - Phase III");
  3521. #endif
  3522. // Phase III - Update Mesh Vertex Data
  3523. if (m_renderMode == TextRenderFlags.Render && IsActive())
  3524. {
  3525. // Event to allow users to modify the content of the text info before the text is rendered.
  3526. OnPreRenderText?.Invoke(m_textInfo);
  3527. // Must ensure the Canvas support the additional vertex attributes used by TMP.
  3528. // This could be optimized based on canvas render mode settings but gets complicated to handle with multiple text objects using different material presets.
  3529. if (m_canvas.additionalShaderChannels != (AdditionalCanvasShaderChannels)25)
  3530. m_canvas.additionalShaderChannels |= (AdditionalCanvasShaderChannels)25;
  3531. // Sort the geometry of the text object if needed.
  3532. if (m_geometrySortingOrder != VertexSortingOrder.Normal)
  3533. m_textInfo.meshInfo[0].SortGeometry(VertexSortingOrder.Reverse);
  3534. // Upload Mesh Data
  3535. m_mesh.MarkDynamic();
  3536. m_mesh.vertices = m_textInfo.meshInfo[0].vertices;
  3537. m_mesh.uv = m_textInfo.meshInfo[0].uvs0;
  3538. m_mesh.uv2 = m_textInfo.meshInfo[0].uvs2;
  3539. //m_mesh.uv4 = m_textInfo.meshInfo[0].uvs4;
  3540. m_mesh.colors32 = m_textInfo.meshInfo[0].colors32;
  3541. // Compute Bounds for the mesh. Manual computation is more efficient then using Mesh.RecalcualteBounds.
  3542. m_mesh.RecalculateBounds();
  3543. //m_mesh.bounds = new Bounds(new Vector3((m_meshExtents.max.x + m_meshExtents.min.x) / 2, (m_meshExtents.max.y + m_meshExtents.min.y) / 2, 0) + offset, new Vector3(m_meshExtents.max.x - m_meshExtents.min.x, m_meshExtents.max.y - m_meshExtents.min.y, 0));
  3544. m_canvasRenderer.SetMesh(m_mesh);
  3545. // Cache CanvasRenderer color of the parent text object.
  3546. Color parentBaseColor = m_canvasRenderer.GetColor();
  3547. bool isCullTransparentMeshEnabled = m_canvasRenderer.cullTransparentMesh;
  3548. for (int i = 1; i < m_textInfo.materialCount; i++)
  3549. {
  3550. // Clear unused vertices
  3551. m_textInfo.meshInfo[i].ClearUnusedVertices();
  3552. if (m_subTextObjects[i] == null) continue;
  3553. // Sort the geometry of the sub-text objects if needed.
  3554. if (m_geometrySortingOrder != VertexSortingOrder.Normal)
  3555. m_textInfo.meshInfo[i].SortGeometry(VertexSortingOrder.Reverse);
  3556. //m_subTextObjects[i].mesh.MarkDynamic();
  3557. m_subTextObjects[i].mesh.vertices = m_textInfo.meshInfo[i].vertices;
  3558. m_subTextObjects[i].mesh.uv = m_textInfo.meshInfo[i].uvs0;
  3559. m_subTextObjects[i].mesh.uv2 = m_textInfo.meshInfo[i].uvs2;
  3560. //m_subTextObjects[i].mesh.uv4 = m_textInfo.meshInfo[i].uvs4;
  3561. m_subTextObjects[i].mesh.colors32 = m_textInfo.meshInfo[i].colors32;
  3562. m_subTextObjects[i].mesh.RecalculateBounds();
  3563. m_subTextObjects[i].canvasRenderer.SetMesh(m_subTextObjects[i].mesh);
  3564. // Set CanvasRenderer color to match the parent text object.
  3565. m_subTextObjects[i].canvasRenderer.SetColor(parentBaseColor);
  3566. // Make sure Cull Transparent Mesh of the sub objects matches the parent
  3567. m_subTextObjects[i].canvasRenderer.cullTransparentMesh = isCullTransparentMeshEnabled;
  3568. // Sync RaycastTarget property with parent text object
  3569. m_subTextObjects[i].raycastTarget = this.raycastTarget;
  3570. }
  3571. }
  3572. // Event indicating the text has been regenerated.
  3573. TMPro_EventManager.ON_TEXT_CHANGED(this);
  3574. //Debug.Log("***** Done rendering text object ID " + GetInstanceID() + ". *****");
  3575. #if TMP_PROFILE_ON
  3576. // End Sampling of Phase III
  3577. Profiler.EndSample();
  3578. // End Sampling of GenerateText()
  3579. Profiler.EndSample();
  3580. #endif
  3581. }
  3582. /// <summary>
  3583. /// Method to return the local corners of the Text Container or RectTransform.
  3584. /// </summary>
  3585. /// <returns></returns>
  3586. protected override Vector3[] GetTextContainerLocalCorners()
  3587. {
  3588. if (m_rectTransform == null) m_rectTransform = this.rectTransform;
  3589. m_rectTransform.GetLocalCorners(m_RectTransformCorners);
  3590. return m_RectTransformCorners;
  3591. }
  3592. /// <summary>
  3593. /// Method to Enable or Disable child SubMesh objects.
  3594. /// </summary>
  3595. /// <param name="state"></param>
  3596. protected override void SetActiveSubMeshes(bool state)
  3597. {
  3598. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  3599. {
  3600. if (m_subTextObjects[i].enabled != state)
  3601. m_subTextObjects[i].enabled = state;
  3602. }
  3603. }
  3604. /// <summary>
  3605. /// Destroy Sub Mesh Objects
  3606. /// </summary>
  3607. protected override void DestroySubMeshObjects()
  3608. {
  3609. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  3610. DestroyImmediate(m_subTextObjects[i]);
  3611. }
  3612. /// <summary>
  3613. /// Method returning the compound bounds of the text object and child sub objects.
  3614. /// </summary>
  3615. /// <returns></returns>
  3616. protected override Bounds GetCompoundBounds()
  3617. {
  3618. Bounds mainBounds = m_mesh.bounds;
  3619. Vector3 min = mainBounds.min;
  3620. Vector3 max = mainBounds.max;
  3621. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  3622. {
  3623. Bounds subBounds = m_subTextObjects[i].mesh.bounds;
  3624. min.x = min.x < subBounds.min.x ? min.x : subBounds.min.x;
  3625. min.y = min.y < subBounds.min.y ? min.y : subBounds.min.y;
  3626. max.x = max.x > subBounds.max.x ? max.x : subBounds.max.x;
  3627. max.y = max.y > subBounds.max.y ? max.y : subBounds.max.y;
  3628. }
  3629. Vector3 center = (min + max) / 2;
  3630. Vector2 size = max - min;
  3631. return new Bounds(center, size);
  3632. }
  3633. internal override Rect GetCanvasSpaceClippingRect()
  3634. {
  3635. if (m_canvas == null || m_canvas.rootCanvas == null || m_mesh == null)
  3636. return Rect.zero;
  3637. Transform rootCanvasTransform = m_canvas.rootCanvas.transform;
  3638. Bounds compoundBounds = GetCompoundBounds();
  3639. Vector2 position = rootCanvasTransform.InverseTransformPoint(m_rectTransform.position);
  3640. Vector2 canvasLossyScale = rootCanvasTransform.lossyScale;
  3641. Vector2 lossyScale = m_rectTransform.lossyScale / canvasLossyScale;
  3642. return new Rect(position + compoundBounds.min * lossyScale, compoundBounds.size * lossyScale);
  3643. }
  3644. /// <summary>
  3645. /// Method to Update Scale in UV2
  3646. /// </summary>
  3647. //void UpdateSDFScale(float lossyScale)
  3648. //{
  3649. // // TODO: Resolve - Underline / Strikethrough segments not getting their SDF Scale adjusted.
  3650. // //Debug.Log("Updating SDF Scale.");
  3651. // // Return if we don't have a valid reference to a Canvas.
  3652. // if (m_canvas == null)
  3653. // {
  3654. // m_canvas = GetCanvas();
  3655. // if (m_canvas == null) return;
  3656. // }
  3657. // lossyScale = lossyScale == 0 ? 1 : lossyScale;
  3658. // float xScale = 0;
  3659. // float canvasScaleFactor = m_canvas.scaleFactor;
  3660. // if (m_canvas.renderMode == RenderMode.ScreenSpaceOverlay)
  3661. // xScale = lossyScale / canvasScaleFactor;
  3662. // else if (m_canvas.renderMode == RenderMode.ScreenSpaceCamera)
  3663. // xScale = m_canvas.worldCamera != null ? lossyScale : 1;
  3664. // else
  3665. // xScale = lossyScale;
  3666. // // Iterate through each of the characters.
  3667. // for (int i = 0; i < m_textInfo.characterCount; i++)
  3668. // {
  3669. // // Only update scale for visible characters.
  3670. // if (m_textInfo.characterInfo[i].isVisible && m_textInfo.characterInfo[i].elementType == TMP_TextElementType.Character)
  3671. // {
  3672. // float scale = xScale * m_textInfo.characterInfo[i].scale * (1 - m_charWidthAdjDelta);
  3673. // if (!m_textInfo.characterInfo[i].isUsingAlternateTypeface && (m_textInfo.characterInfo[i].style & FontStyles.Bold) == FontStyles.Bold) scale *= -1;
  3674. // int index = m_textInfo.characterInfo[i].materialReferenceIndex;
  3675. // int vertexIndex = m_textInfo.characterInfo[i].vertexIndex;
  3676. // m_textInfo.meshInfo[index].uvs2[vertexIndex + 0].y = scale;
  3677. // m_textInfo.meshInfo[index].uvs2[vertexIndex + 1].y = scale;
  3678. // m_textInfo.meshInfo[index].uvs2[vertexIndex + 2].y = scale;
  3679. // m_textInfo.meshInfo[index].uvs2[vertexIndex + 3].y = scale;
  3680. // }
  3681. // }
  3682. // // Push the updated uv2 scale information to the meshes.
  3683. // for (int i = 0; i < m_textInfo.materialCount; i++)
  3684. // {
  3685. // if (i == 0)
  3686. // {
  3687. // m_mesh.uv2 = m_textInfo.meshInfo[0].uvs2;
  3688. // m_canvasRenderer.SetMesh(m_mesh);
  3689. // }
  3690. // else
  3691. // {
  3692. // m_subTextObjects[i].mesh.uv2 = m_textInfo.meshInfo[i].uvs2;
  3693. // m_subTextObjects[i].canvasRenderer.SetMesh(m_subTextObjects[i].mesh);
  3694. // }
  3695. // }
  3696. //}
  3697. /// <summary>
  3698. /// Method to update the SDF Scale in UV2.
  3699. /// </summary>
  3700. /// <param name="scaleDelta"></param>
  3701. void UpdateSDFScale(float scaleDelta)
  3702. {
  3703. if (scaleDelta == 0 || scaleDelta == float.PositiveInfinity || scaleDelta == float.NegativeInfinity)
  3704. {
  3705. m_havePropertiesChanged = true;
  3706. OnPreRenderCanvas();
  3707. return;
  3708. }
  3709. for (int materialIndex = 0; materialIndex < m_textInfo.materialCount; materialIndex ++)
  3710. {
  3711. TMP_MeshInfo meshInfo = m_textInfo.meshInfo[materialIndex];
  3712. for (int i = 0; i < meshInfo.uvs2.Length; i++)
  3713. {
  3714. meshInfo.uvs2[i].y *= Mathf.Abs(scaleDelta);
  3715. }
  3716. }
  3717. // Push the updated uv2 scale information to the meshes.
  3718. for (int i = 0; i < m_textInfo.materialCount; i++)
  3719. {
  3720. if (i == 0)
  3721. {
  3722. m_mesh.uv2 = m_textInfo.meshInfo[0].uvs2;
  3723. m_canvasRenderer.SetMesh(m_mesh);
  3724. }
  3725. else
  3726. {
  3727. m_subTextObjects[i].mesh.uv2 = m_textInfo.meshInfo[i].uvs2;
  3728. m_subTextObjects[i].canvasRenderer.SetMesh(m_subTextObjects[i].mesh);
  3729. }
  3730. }
  3731. }
  3732. }
  3733. }