TMPro_Private.cs 227 KB

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