Nav apraksta
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

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