TextMeshPro.ts 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. import TmpAssembler from "./utils/TmpAssembler";
  2. import TmpFontConfig from "./utils/TmpFontConfig";
  3. import TmpUtils from "./utils/TmpUtils";
  4. const { ccclass, property, executeInEditMode, menu } = cc._decorator;
  5. /**
  6. * TextMeshPro的排版方式
  7. */
  8. export enum TmpOverflow {
  9. NONE,
  10. CLAMP,
  11. ELLIPSIS,
  12. SHRINK,
  13. RESIZE_HEIGHT
  14. }
  15. /**
  16. * TextMeshPro Uniform参数
  17. */
  18. @ccclass("TmpUniform")
  19. export class TmpUniform {
  20. @property(cc.Color)
  21. private _faceColor: cc.Color = cc.Color.WHITE;
  22. @property({ tooltip: CC_DEV && "文本主体颜色", type: cc.Color })
  23. public get faceColor(): cc.Color { return this._faceColor; }
  24. public set faceColor(v: cc.Color) {
  25. if (!CC_EDITOR && this._faceColor === v) { return; }
  26. this._faceColor = v;
  27. if (!this._comp) { return; }
  28. this._comp.updateTmpMatFace(this._comp.getMaterial(0));
  29. }
  30. @property()
  31. private _faceDilate: number = 0.5;
  32. @property({ tooltip: CC_DEV && "文本主体厚度", range: [0, 1, 0.01] })
  33. public get faceDilate(): number { return this._faceDilate; }
  34. public set faceDilate(v: number) {
  35. if (this._faceDilate === v) { return; }
  36. this._faceDilate = v;
  37. if (!this._comp) { return; }
  38. this._comp.updateTmpMatFace(this._comp.getMaterial(0));
  39. }
  40. @property()
  41. private _faceSoftness: number = 0.01;
  42. @property({ tooltip: CC_DEV && "文本主体柔和度", range: [0, 1, 0.01] })
  43. public get faceSoftness(): number { return this._faceSoftness; }
  44. public set faceSoftness(v: number) {
  45. if (this._faceSoftness === v) { return; }
  46. this._faceSoftness = v;
  47. if (!this._comp) { return; }
  48. this._comp.updateTmpMatFace(this._comp.getMaterial(0));
  49. }
  50. @property()
  51. private _enableOutline: boolean = false;
  52. @property({ tooltip: CC_DEV && "是否启用描边效果" })
  53. public get enableOutline(): boolean { return this._enableOutline; }
  54. public set enableOutline(v: boolean) {
  55. if (this._enableOutline === v) { return; }
  56. this._enableOutline = v;
  57. if (!this._comp) { return; }
  58. this._comp.updateTmpMatOutline(this._comp.getMaterial(0));
  59. }
  60. @property(cc.Color)
  61. private _outlineColor: cc.Color = cc.color(255, 0, 0, 255);
  62. @property({
  63. tooltip: CC_DEV && "描边颜色",
  64. type: cc.Color,
  65. visible() { return this._enableOutline; }
  66. })
  67. public get outlineColor(): cc.Color { return this._outlineColor; }
  68. public set outlineColor(v: cc.Color) {
  69. if (!CC_EDITOR && this._outlineColor === v) { return; }
  70. this._outlineColor = v;
  71. if (!this._comp) { return; }
  72. this._comp.updateTmpMatOutline(this._comp.getMaterial(0));
  73. }
  74. @property()
  75. private _outlineThickness: number = 0.1;
  76. @property({
  77. tooltip: CC_DEV && "描边厚度",
  78. range: [0, 1, 0.01],
  79. visible() { return this._enableOutline; }
  80. })
  81. public get outlineThickness(): number { return this._outlineThickness; }
  82. public set outlineThickness(v: number) {
  83. if (this._outlineThickness === v) { return; }
  84. this._outlineThickness = v;
  85. if (!this._comp) { return; }
  86. this._comp.updateTmpMatOutline(this._comp.getMaterial(0));
  87. }
  88. @property()
  89. private _enableUnderlay: boolean = false;
  90. @property({ tooltip: CC_DEV && "是否启用阴影效果" })
  91. public get enableUnderlay(): boolean { return this._enableUnderlay; }
  92. public set enableUnderlay(v: boolean) {
  93. if (this._enableUnderlay === v) { return; }
  94. this._enableUnderlay = v;
  95. if (!this._comp) { return; }
  96. this._comp.updateTmpMatUnderlay(this._comp.getMaterial(0));
  97. }
  98. @property(cc.Color)
  99. private _underlayColor: cc.Color = cc.color(0, 0, 0, 255);
  100. @property({
  101. tooltip: CC_DEV && "阴影颜色",
  102. type: cc.Color,
  103. visible() { return this._enableUnderlay; }
  104. })
  105. public get underlayColor(): cc.Color { return this._underlayColor; }
  106. public set underlayColor(v: cc.Color) {
  107. if (!CC_EDITOR && this._underlayColor === v) { return; }
  108. this._underlayColor = v;
  109. if (!this._comp) { return; }
  110. this._comp.updateTmpMatUnderlay(this._comp.getMaterial(0));
  111. }
  112. @property(cc.Vec2)
  113. private _underlayOffset: cc.Vec2 = cc.v2(0, 0);
  114. @property({
  115. tooltip: CC_DEV && "阴影偏移",
  116. type: cc.Vec2,
  117. range: [-1, 1],
  118. visible() { return this._enableUnderlay; }
  119. })
  120. public get underlayOffset(): cc.Vec2 { return this._underlayOffset; }
  121. public set underlayOffset(v: cc.Vec2) {
  122. if (!CC_EDITOR && this._underlayOffset === v) { return; }
  123. this._underlayOffset = v;
  124. if (!this._comp) { return; }
  125. this._comp.updateTmpMatUnderlay(this._comp.getMaterial(0));
  126. }
  127. @property()
  128. private _underlayDilate: number = 0.5;
  129. @property({
  130. tooltip: CC_DEV && "阴影厚度",
  131. range: [0, 1, 0.01],
  132. visible() { return this._enableUnderlay; }
  133. })
  134. public get underlayDilate(): number { return this._underlayDilate; }
  135. public set underlayDilate(v: number) {
  136. if (this._underlayDilate === v) { return; }
  137. this._underlayDilate = v;
  138. if (!this._comp) { return; }
  139. this._comp.updateTmpMatUnderlay(this._comp.getMaterial(0));
  140. }
  141. @property()
  142. private _underlaySoftness: number = 0.1;
  143. @property({
  144. tooltip: CC_DEV && "阴影柔和度",
  145. range: [0, 1, 0.01],
  146. visible() { return this._enableUnderlay; }
  147. })
  148. public get underlaySoftness(): number { return this._underlaySoftness; }
  149. public set underlaySoftness(v: number) {
  150. if (this._underlaySoftness === v) { return; }
  151. this._underlaySoftness = v;
  152. if (!this._comp) { return; }
  153. this._comp.updateTmpMatUnderlay(this._comp.getMaterial(0));
  154. }
  155. @property()
  156. private _enableGlow: boolean = false;
  157. @property({ tooltip: CC_DEV && "是否启用辉光效果" })
  158. public get enableGlow(): boolean { return this._enableGlow; }
  159. public set enableGlow(v: boolean) {
  160. if (this._enableGlow === v) { return; }
  161. this._enableGlow = v;
  162. if (!this._comp) { return; }
  163. this._comp.updateTmpMatGlow(this._comp.getMaterial(0));
  164. }
  165. @property(cc.Color)
  166. private _glowColor: cc.Color = cc.color(0, 255, 0, 255);
  167. @property({
  168. tooltip: CC_DEV && "辉光颜色",
  169. type: cc.Color,
  170. visible() { return this._enableGlow; }
  171. })
  172. public get glowColor(): cc.Color { return this._glowColor; }
  173. public set glowColor(v: cc.Color) {
  174. if (!CC_EDITOR && this._glowColor === v) { return; }
  175. this._glowColor = v;
  176. if (!this._comp) { return; }
  177. this._comp.updateTmpMatGlow(this._comp.getMaterial(0));
  178. }
  179. @property()
  180. private _glowOffset: number = 0.5;
  181. @property({
  182. tooltip: CC_DEV && "辉光偏移",
  183. range: [0, 1, 0.01],
  184. visible() { return this._enableGlow; }
  185. })
  186. public get glowOffset(): number { return this._glowOffset; }
  187. public set glowOffset(v: number) {
  188. if (this._glowOffset === v) { return; }
  189. this._glowOffset = v;
  190. if (!this._comp) { return; }
  191. this._comp.updateTmpMatGlow(this._comp.getMaterial(0));
  192. }
  193. @property()
  194. private _glowInner: number = 0.01;
  195. @property({
  196. tooltip: CC_DEV && "辉光向内的厚度",
  197. range: [0, 1, 0.01],
  198. visible() { return this._enableGlow; }
  199. })
  200. public get glowInner(): number { return this._glowInner; }
  201. public set glowInner(v: number) {
  202. if (this._glowInner === v) { return; }
  203. this._glowInner = v;
  204. if (!this._comp) { return; }
  205. this._comp.updateTmpMatGlow(this._comp.getMaterial(0));
  206. }
  207. @property()
  208. private _glowOuter: number = 0.01;
  209. @property({
  210. tooltip: CC_DEV && "辉光向外的厚度",
  211. range: [0, 1, 0.01],
  212. visible() { return this._enableGlow; }
  213. })
  214. public get glowOuter(): number { return this._glowOuter; }
  215. public set glowOuter(v: number) {
  216. if (this._glowOuter === v) { return; }
  217. this._glowOuter = v;
  218. if (!this._comp) { return; }
  219. this._comp.updateTmpMatGlow(this._comp.getMaterial(0));
  220. }
  221. @property()
  222. private _glowPower: number = 1;
  223. @property({
  224. tooltip: CC_DEV && "辉光强度",
  225. range: [0, 1, 0.01],
  226. visible() { return this._enableGlow; }
  227. })
  228. public get glowPower(): number { return this._glowPower; }
  229. public set glowPower(v: number) {
  230. if (this._glowPower === v) { return; }
  231. this._glowPower = v;
  232. if (!this._comp) { return; }
  233. this._comp.updateTmpMatGlow(this._comp.getMaterial(0));
  234. }
  235. private _comp: TextMeshPro = null;
  236. public get comp(): TextMeshPro { return this._comp; }
  237. public init(text: TextMeshPro) {
  238. this._comp = text;
  239. if (CC_EDITOR) {
  240. return;
  241. }
  242. let material = this._comp.getMaterial(0);
  243. this._comp.updateTmpMatFace(material);
  244. this._comp.updateTmpMatOutline(material);
  245. this._comp.updateTmpMatUnderlay(material);
  246. this._comp.updateTmpMatGlow(material);
  247. }
  248. }
  249. @ccclass
  250. @executeInEditMode
  251. @menu("TextMeshPro组件/TextMeshPro")
  252. export default class TextMeshPro extends cc.RenderComponent {
  253. @property
  254. private _string: string = "";
  255. @property({ multiline: true })
  256. public get string(): string { return this._string; }
  257. public set string(v: string) {
  258. if (this._string === v) { return; }
  259. this._string = v;
  260. this["setVertsDirty"]();
  261. this._checkStringEmpty();
  262. }
  263. @property(cc.JsonAsset)
  264. private _font: cc.JsonAsset = null;
  265. @property({ tooltip: CC_DEV && "字体资源\n依赖的纹理请勿打入图集\n在编辑器内拖拽此文件时,纹理必须和此文件处于同一目录下", type: cc.JsonAsset })
  266. private get font(): cc.JsonAsset { return this._font; }
  267. private set font(v: cc.JsonAsset) {
  268. if (this._font === v) { return; }
  269. this._font = v;
  270. if (CC_EDITOR) {
  271. this.editorInit();
  272. } else {
  273. if (!this.enabledInHierarchy) { return; }
  274. this.forceUpdateRenderData();
  275. }
  276. }
  277. @property({ type: cc.Label.HorizontalAlign })
  278. private _horizontalAlign: cc.Label.HorizontalAlign = cc.Label.HorizontalAlign.LEFT;
  279. @property({ type: cc.Label.HorizontalAlign })
  280. public get horizontalAlign(): cc.Label.HorizontalAlign { return this._horizontalAlign; }
  281. public set horizontalAlign(v: cc.Label.HorizontalAlign) {
  282. if (this._horizontalAlign === v) { return; }
  283. this._horizontalAlign = v;
  284. this["setVertsDirty"]();
  285. }
  286. @property({ type: cc.Label.VerticalAlign })
  287. private _verticalAlign: cc.Label.VerticalAlign = cc.Label.VerticalAlign.TOP;
  288. @property({ type: cc.Label.VerticalAlign })
  289. public get verticalAlign(): cc.Label.VerticalAlign { return this._verticalAlign; }
  290. public set verticalAlign(v: cc.Label.VerticalAlign) {
  291. if (this._verticalAlign === v) { return; }
  292. this._verticalAlign = v;
  293. this["setVertsDirty"]();
  294. }
  295. @property
  296. private _actualFontSize: number = 0;
  297. @property({ visible() { return this._overflow === TmpOverflow.SHRINK; } })
  298. public get actualFontSize(): number { return this._actualFontSize; }
  299. @property
  300. public get bmfontOriginalSize(): number { return this.font ? this.font.json.size : -1; }
  301. @property
  302. private _fontSize: number = 32;
  303. @property({ range: [0, 1024] })
  304. public get fontSize(): number { return this._fontSize; }
  305. public set fontSize(v: number) {
  306. if (this._fontSize === v) { return; }
  307. this._fontSize = v;
  308. this["setVertsDirty"]();
  309. }
  310. @property
  311. private _lineHeight: number = 32;
  312. @property
  313. public get lineHeight(): number { return this._lineHeight; }
  314. public set lineHeight(v: number) {
  315. if (this._lineHeight === v) { return; }
  316. this._lineHeight = v;
  317. this["setVertsDirty"]();
  318. }
  319. @property
  320. private _spacingX: number = 0;
  321. @property
  322. public get spacingX(): number { return this._spacingX; }
  323. public set spacingX(v: number) {
  324. if (this._spacingX === v) { return; }
  325. this._spacingX = v;
  326. this["setVertsDirty"]();
  327. }
  328. @property({ type: cc.Enum(TmpOverflow) })
  329. private _overflow: TmpOverflow = TmpOverflow.NONE;
  330. @property({ tooltip: CC_DEV && "文本的排版方式", type: cc.Enum(TmpOverflow) })
  331. public get overflow(): TmpOverflow { return this._overflow; }
  332. public set overflow(v: TmpOverflow) {
  333. if (this._overflow === v) { return; }
  334. this._overflow = v;
  335. this["setVertsDirty"]();
  336. }
  337. @property
  338. private _enableWrapText: boolean = true;
  339. @property({
  340. tooltip: CC_DEV && "是否启用自动换行",
  341. visible() {
  342. return this._overflow === TmpOverflow.CLAMP || this._overflow === TmpOverflow.ELLIPSIS;
  343. }
  344. })
  345. public get enableWrapText(): boolean { return this._enableWrapText; }
  346. public set enableWrapText(v: boolean) {
  347. if (this._enableWrapText === v) { return; }
  348. this._enableWrapText = v;
  349. this["setVertsDirty"]();
  350. }
  351. @property
  352. private _enableItalic: boolean = false;
  353. @property({ tooltip: CC_DEV && "是否启用斜体" })
  354. public get enableItalic(): boolean { return this._enableItalic; }
  355. public set enableItalic(v: boolean) {
  356. if (this._enableItalic === v) { return; }
  357. this._enableItalic = v;
  358. this["setVertsDirty"]();
  359. }
  360. @property
  361. private _enableUnderline: boolean = false;
  362. @property({ tooltip: CC_DEV && "是否启用下划线" })
  363. public get enableUnderline(): boolean { return this._enableUnderline; }
  364. public set enableUnderline(v: boolean) {
  365. if (this._enableUnderline === v) { return; }
  366. this._enableUnderline = v;
  367. this["setVertsDirty"]();
  368. }
  369. @property
  370. private _underlineOffset: number = 0;
  371. @property({ tooltip: CC_DEV && "下划线高度偏移", visible() { return this._enableUnderline; } })
  372. public get underlineOffset(): number { return this._underlineOffset; }
  373. public set underlineOffset(v: number) {
  374. if (this._underlineOffset === v) { return; }
  375. this._underlineOffset = v;
  376. this["setVertsDirty"]();
  377. }
  378. @property
  379. private _enableStrikethrough: boolean = false;
  380. @property({ tooltip: CC_DEV && "是否启用删除线" })
  381. public get enableStrikethrough(): boolean { return this._enableStrikethrough; }
  382. public set enableStrikethrough(v: boolean) {
  383. if (this._enableStrikethrough === v) { return; }
  384. this._enableStrikethrough = v;
  385. this["setVertsDirty"]();
  386. }
  387. @property
  388. private _strikethroughOffset: number = 0;
  389. @property({ tooltip: CC_DEV && "删除线高度偏移", visible() { return this._enableStrikethrough; } })
  390. public get strikethroughOffset(): number { return this._strikethroughOffset; }
  391. public set strikethroughOffset(v: number) {
  392. if (this._strikethroughOffset === v) { return; }
  393. this._strikethroughOffset = v;
  394. this["setVertsDirty"]();
  395. }
  396. @property
  397. private _colorGradient: boolean = false;
  398. @property({ tooltip: CC_DEV && "是否启用颜色渐变,会和顶点颜色混合为最终的顶点颜色" })
  399. public get colorGradient(): boolean { return this._colorGradient; }
  400. public set colorGradient(v: boolean) {
  401. if (this._colorGradient === v) { return; }
  402. this._colorGradient = v;
  403. this._colorExtraDirty = true;
  404. }
  405. @property(cc.Color)
  406. private _colorLB: cc.Color = cc.Color.WHITE;
  407. @property({ tooltip: CC_DEV && "左下顶点", type: cc.Color, visible() { return this._colorGradient; } })
  408. public get colorLB(): cc.Color { return this._colorLB; }
  409. public set colorLB(v: cc.Color) {
  410. if (!CC_EDITOR && this._colorLB === v) { return; }
  411. this._colorLB = v;
  412. this._colorExtraDirty = true;
  413. }
  414. @property(cc.Color)
  415. private _colorRB: cc.Color = cc.Color.WHITE;
  416. @property({ tooltip: CC_DEV && "右下顶点", type: cc.Color, visible() { return this._colorGradient; } })
  417. public get colorRB(): cc.Color { return this._colorRB; }
  418. public set colorRB(v: cc.Color) {
  419. if (!CC_EDITOR && this._colorRB === v) { return; }
  420. this._colorRB = v;
  421. this._colorExtraDirty = true;
  422. }
  423. @property(cc.Color)
  424. private _colorLT: cc.Color = cc.Color.WHITE;
  425. @property({ tooltip: CC_DEV && "左上顶点", type: cc.Color, visible() { return this._colorGradient; } })
  426. public get colorLT(): cc.Color { return this._colorLT; }
  427. public set colorLT(v: cc.Color) {
  428. if (!CC_EDITOR && this._colorLT === v) { return; }
  429. this._colorLT = v;
  430. this._colorExtraDirty = true;
  431. }
  432. @property(cc.Color)
  433. private _colorRT: cc.Color = cc.Color.WHITE;
  434. @property({ tooltip: CC_DEV && "右上顶点", type: cc.Color, visible() { return this._colorGradient; } })
  435. public get colorRT(): cc.Color { return this._colorRT; }
  436. public set colorRT(v: cc.Color) {
  437. if (!CC_EDITOR && this._colorRT === v) { return; }
  438. this._colorRT = v;
  439. this._colorExtraDirty = true;
  440. }
  441. @property({ tooltip: CC_DEV && "材质参数", type: TmpUniform })
  442. public tmpUniform: TmpUniform = new TmpUniform();
  443. @property({ tooltip: CC_DEV && "字体所依赖的纹理", type: cc.Texture2D, readonly: true })
  444. public textures: cc.Texture2D[] = [];
  445. private _fontConfig: TmpFontConfig = null;
  446. /** 字体配置管理 */
  447. public get fontConfig(): TmpFontConfig { return this._fontConfig; }
  448. protected _assembler: TmpAssembler = null;
  449. private _worldVertsDirty: boolean = false;
  450. private _colorExtraDirty: boolean = false;
  451. private _richTextDeltaX: number = 0;
  452. /** 记录letterRight与nextTokenX的差值,供富文本排版使用 */
  453. public get richTextDeltaX(): number { return this._richTextDeltaX; }
  454. private editorInit(): void {
  455. if (CC_EDITOR) {
  456. // 加载图集
  457. if (!this._font || !this._font["_uuid"]) {
  458. this.textures = [];
  459. this.forceUpdateRenderData();
  460. return;
  461. }
  462. // cc.log(this._font["_uuid"]);
  463. Editor.assetdb.queryUrlByUuid(this._font["_uuid"], (error: any, url: string) => {
  464. // cc.log(url);
  465. if (!url) {
  466. return;
  467. }
  468. let start = 12;
  469. let end = url.lastIndexOf("/");
  470. let dir = url.slice(start, end + 1);
  471. let arr: Promise<cc.Texture2D>[] = [];
  472. this._font.json.pageData.forEach((v) => {
  473. let imgUrl = dir + v.file;
  474. arr.push(TmpUtils.load<cc.Texture2D>(imgUrl));
  475. });
  476. Promise.all(arr).then((v) => {
  477. this.textures = v;
  478. this._fontConfig = new TmpFontConfig(this._font.json, this.textures);
  479. if (!this.enabledInHierarchy) { return; }
  480. this.forceUpdateRenderData();
  481. this._onBMFontTextureLoaded();
  482. });
  483. });
  484. }
  485. }
  486. protected resetInEditor(): void {
  487. if (CC_EDITOR) {
  488. TmpUtils.load<cc.Material>(TmpUtils.TMP_MAT).then((mat) => {
  489. if (mat) {
  490. this.setMaterial(0, mat);
  491. }
  492. });
  493. }
  494. }
  495. protected onLoad(): void {
  496. this.editorInit();
  497. this.tmpUniform.init(this);
  498. if (!this._fontConfig && this.font && this.textures.length > 0) {
  499. this._fontConfig = new TmpFontConfig(this._font.json, this.textures);
  500. }
  501. }
  502. protected onEnable(): void {
  503. super.onEnable();
  504. this.node.on(cc.Node.EventType.SIZE_CHANGED, this._nodeSizeChanged, this);
  505. this.node.on(cc.Node.EventType.ANCHOR_CHANGED, this["setVertsDirty"], this);
  506. this.forceUpdateRenderData();
  507. }
  508. protected onDisable(): void {
  509. super.onDisable();
  510. this.node.off(cc.Node.EventType.SIZE_CHANGED, this._nodeSizeChanged, this);
  511. this.node.off(cc.Node.EventType.ANCHOR_CHANGED, this["setVertsDirty"], this);
  512. }
  513. protected lateUpdate(dt: number): void {
  514. if (this._worldVertsDirty) {
  515. this._worldVertsDirty = false;
  516. this._assembler.updateWorldVerts(this);
  517. }
  518. if (this._colorExtraDirty) {
  519. this._colorExtraDirty = false;
  520. this._assembler.updateColorExtra(this);
  521. }
  522. }
  523. private _nodeSizeChanged(): void {
  524. // Because the content size is automatically updated when overflow is NONE.
  525. // And this will conflict with the alignment of the CCWidget.
  526. if (CC_EDITOR || this.overflow !== TmpOverflow.NONE) {
  527. this["setVertsDirty"]();
  528. }
  529. }
  530. private _validateRender(): void {
  531. if (!this.string) {
  532. this["disableRender"]();
  533. return;
  534. }
  535. if (this.getMaterial(0)) {
  536. if (this.textures.length > 0) {
  537. return;
  538. }
  539. }
  540. this["disableRender"]();
  541. }
  542. protected _resetAssembler(): void {
  543. cc.RenderComponent.prototype["_resetAssembler"].call(this);
  544. }
  545. private _checkStringEmpty(): void {
  546. this["markForRender"](!!this.string);
  547. }
  548. private _on3DNodeChanged(): void {
  549. this._resetAssembler();
  550. this._applyFontTexture();
  551. }
  552. private _onBMFontTextureLoaded(): void {
  553. this["markForRender"](true);
  554. this._updateMaterial();
  555. }
  556. private _onBlendChanged(): void {
  557. if (!this.enabledInHierarchy) return;
  558. this.forceUpdateRenderData();
  559. }
  560. private _applyFontTexture(): void {
  561. this["markForValidate"]();
  562. }
  563. private _updateMaterial(): void {
  564. let material = this.getMaterial(0);
  565. if (!material) {
  566. return;
  567. }
  568. cc.BlendFunc.prototype["_updateMaterialBlendFunc"].call(this, material);
  569. // 更新材质参数
  570. this._updateTmpMatTexture(material);
  571. if (!this.tmpUniform || !this.tmpUniform.comp) {
  572. return;
  573. }
  574. this.updateTmpMatFace(material);
  575. this.updateTmpMatOutline(material);
  576. this.updateTmpMatUnderlay(material);
  577. this.updateTmpMatGlow(material);
  578. }
  579. public _updateTmpMatTexture(material: cc.Material): void {
  580. if (!material || this.textures.length <= 0) {
  581. return;
  582. }
  583. material.define("USE_TEXTURE_LEVEL_1", this.textures.length > 0);
  584. material.define("USE_TEXTURE_LEVEL_2", this.textures.length > 1);
  585. material.define("USE_TEXTURE_LEVEL_3", this.textures.length > 2);
  586. material.define("USE_TEXTURE_LEVEL_4", this.textures.length > 4);
  587. for (let i = 0; i < this.textures.length; i++) {
  588. material.setProperty(`texture${i}`, this.textures[i]);
  589. }
  590. material["_effect"]._dirty = true;
  591. }
  592. public updateTmpMatFace(material: cc.Material): void {
  593. if (!material) {
  594. return;
  595. }
  596. material.setProperty("faceColor", this.tmpUniform.faceColor);
  597. material.setProperty("faceDilate", this.tmpUniform.faceDilate);
  598. material.setProperty("faceSoftness", this.tmpUniform.faceSoftness);
  599. material["_effect"]._dirty = true;
  600. }
  601. public updateTmpMatOutline(material: cc.Material): void {
  602. if (!material) {
  603. return;
  604. }
  605. material.define("USE_OUTLINE", this.tmpUniform.enableOutline);
  606. if (this.tmpUniform.enableOutline) {
  607. material.setProperty("outlineColor", this.tmpUniform.outlineColor);
  608. material.setProperty("outlineThickness", this.tmpUniform.outlineThickness);
  609. }
  610. material["_effect"]._dirty = true;
  611. }
  612. public updateTmpMatUnderlay(material: cc.Material): void {
  613. if (!material) {
  614. return;
  615. }
  616. material.define("USE_UNDERLAY", this.tmpUniform.enableUnderlay);
  617. if (this.tmpUniform.enableUnderlay) {
  618. material.setProperty("underlayColor", this.tmpUniform.underlayColor);
  619. material.setProperty("underlayOffsetX", this.tmpUniform.underlayOffset.x);
  620. material.setProperty("underlayOffsetY", this.tmpUniform.underlayOffset.y);
  621. material.setProperty("underlayDilate", this.tmpUniform.underlayDilate);
  622. material.setProperty("underlaySoftness", this.tmpUniform.underlaySoftness);
  623. }
  624. material["_effect"]._dirty = true;
  625. }
  626. public updateTmpMatGlow(material: cc.Material): void {
  627. if (!material) {
  628. return;
  629. }
  630. material.define("USE_GLOW", this.tmpUniform.enableGlow);
  631. if (this.tmpUniform.enableGlow) {
  632. material.setProperty("glowColor", this.tmpUniform.glowColor);
  633. material.setProperty("glowOffset", this.tmpUniform.glowOffset);
  634. material.setProperty("glowInner", this.tmpUniform.glowInner);
  635. material.setProperty("glowOuter", this.tmpUniform.glowOuter);
  636. material.setProperty("glowPower", this.tmpUniform.glowPower);
  637. }
  638. material["_effect"]._dirty = true;
  639. }
  640. /**
  641. * 立即更新渲染数据
  642. */
  643. public forceUpdateRenderData(): void {
  644. this["setVertsDirty"]();
  645. this._resetAssembler();
  646. this._applyFontTexture();
  647. this._assembler && this._assembler.updateRenderData(this);
  648. this.node["_renderFlag"] |= cc["RenderFlow"].FLAG_COLOR;
  649. }
  650. /**
  651. * 设置字体,必须调用此接口去动态设置字体
  652. */
  653. public setFont(font: cc.JsonAsset, textures: cc.Texture2D[]): void {
  654. if (!font || textures.length < 0) {
  655. cc.error(`please check your font!`);
  656. return;
  657. }
  658. this._font = font;
  659. this.textures = textures;
  660. this._fontConfig = new TmpFontConfig(this._font.json, this.textures);
  661. if (!this.enabledInHierarchy) { return; }
  662. this.forceUpdateRenderData();
  663. this._onBMFontTextureLoaded();
  664. }
  665. //#region 顶点数据操作接口,必须保证组件启用且节点激活才可使用这些接口
  666. /**
  667. * 根据字符下标判断此字符是否可见
  668. */
  669. public isVisible(index: number): boolean {
  670. if (!this.enabledInHierarchy) { return false; }
  671. return this._assembler.isVisble(index);
  672. }
  673. /**
  674. * 根据字符下标设置字符是否可见
  675. */
  676. public setVisible(index: number, visible: boolean): void {
  677. if (!this.enabledInHierarchy) { return; }
  678. this._assembler.setVisible(this, index, visible);
  679. }
  680. /**
  681. * 根据字符下标获取颜色顶点数据,顺序为[左下, 右下, 左上, 右上]
  682. */
  683. public getColorExtraVertices(index: number): [cc.Color, cc.Color, cc.Color, cc.Color] | null {
  684. if (!this.enabledInHierarchy) { return null; }
  685. return this._assembler.getColorExtraVertices(index);
  686. }
  687. /**
  688. * 根据字符下标设置颜色顶点数据,会和节点颜色混合为最终的顶点颜色,顺序为[左下, 右下, 左上, 右上]
  689. */
  690. public setColorExtraVertices(index: number, data: [cc.Color, cc.Color, cc.Color, cc.Color]): void {
  691. if (!this.enabledInHierarchy) { return; }
  692. this._assembler.setColorExtraVertices(index, data);
  693. }
  694. /**
  695. * 根据字符下标获取坐标顶点数据,顺序为[左下, 右下, 左上, 右上]
  696. */
  697. public getPosVertices(index: number): [cc.Vec2, cc.Vec2, cc.Vec2, cc.Vec2] | null {
  698. if (!this.enabledInHierarchy) { return null; }
  699. return this._assembler.getPosVertices(index);
  700. }
  701. /**
  702. * 根据字符下标设置坐标顶点数据,顺序为[左下, 右下, 左上, 右上]
  703. */
  704. public setPosVertices(index: number, data: [cc.Vec2, cc.Vec2, cc.Vec2, cc.Vec2]): void {
  705. if (!this.enabledInHierarchy) { return; }
  706. this._assembler.setPosVertices(index, data);
  707. this._worldVertsDirty = true;
  708. }
  709. //#endregion
  710. }
  711. cc["Assembler"].register(TextMeshPro, {
  712. getConstructor(comp: TextMeshPro) {
  713. return TmpAssembler;
  714. }
  715. });