TmpAssembler.ts 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282
  1. import TextMeshPro, { TmpOverflow } from "../TextMeshPro";
  2. import TmpFontConfig, { TmpFontLetter } from "./TmpFontConfig";
  3. const gfx = cc["gfx"];
  4. const vfmt = new gfx.VertexFormat([
  5. { name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
  6. { name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
  7. { name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
  8. { name: "a_color_extra", type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
  9. { name: "a_texture_idx", type: gfx.ATTR_TYPE_FLOAT32, num: 1 },
  10. ]);
  11. const WHITE = cc.Color.WHITE;
  12. /** 斜体倾斜弧度值 */
  13. const ITALIC_REDIANS = cc.misc.degreesToRadians(15);
  14. /** 下划线字符code */
  15. const UNDERLINE_CODE = 95;
  16. /** 省略号字符code */
  17. const ELLIPSIS_CODE = 46;
  18. const ELLIPSIS_CHAR = ".";
  19. const ELLIPSIS_NUM = 3;
  20. // share data of bmfont
  21. let shareLabelInfo = {
  22. fontAtlas: null as TmpFontConfig,
  23. fontSize: 0,
  24. lineHeight: 0,
  25. hAlign: 0,
  26. vAlign: 0,
  27. hash: "",
  28. margin: 0,
  29. };
  30. let _comp: TextMeshPro = null;
  31. let _tmpUvRect = cc.rect();
  32. let _tmpPosRect = cc.rect();
  33. let _horizontalKernings = [];
  34. let _linesWidth = [];
  35. let _linesOffsetX = [];
  36. let _fntConfig: TmpFontConfig = null;
  37. let _numberOfLines = 0;
  38. let _textDesiredHeight = 0;
  39. let _letterOffsetY = 0;
  40. let _tailoredTopY = 0;
  41. let _tailoredBottomY = 0;
  42. let _bmfontScale = 1.0;
  43. let _lineBreakWithoutSpaces = false;
  44. let _lineSpacing = 0;
  45. let _contentSize = cc.size(0, 0);
  46. let _string = "";
  47. let _fontSize = 0;
  48. let _originFontSize = 0;
  49. let _hAlign = 0;
  50. let _vAlign = 0;
  51. let _spacingX = 0;
  52. let _lineHeight = 0;
  53. let _overflow: TmpOverflow = 0;
  54. let _isWrapText = false;
  55. let _labelWidth = 0;
  56. let _labelHeight = 0;
  57. let _maxLineWidth = 0;
  58. let _dataOffset = 0;
  59. /** 斜体计算向量 */
  60. let _italicVec = cc.v2();
  61. /** 画下划线、删除线所需的数据 */
  62. let _extraLinesData: { [lineIndex: number]: { lineIndex: number, first: any, last: any } } = {};
  63. let _extraLineDef: TmpFontLetter = null;
  64. /** 省略号所需的数据 */
  65. let _ellipsisDef: TmpFontLetter = null;
  66. let _ellipsisWidth: number = 0;
  67. /**
  68. * 字符渲染数据
  69. */
  70. class LetterInfo {
  71. /** 标记字符是否需要渲染 */
  72. public valid = true;
  73. public char = "";
  74. public x = 0;
  75. public y = 0;
  76. public line = 0;
  77. public hash = "";
  78. /** 标记处于需要渲染的字符中的第几位 */
  79. public quadsIndex = 0;
  80. /** 主动设置字符是否可见 */
  81. public visible = true;
  82. }
  83. /**
  84. * TextMeshPro顶点数据管理
  85. */
  86. export default class TmpAssembler extends cc["Assembler"] {
  87. /** 每个顶点的数据长度 */
  88. protected floatsPerVert: number = 7;
  89. protected verticesCount: number = 4;
  90. protected indicesCount: number = 6;
  91. protected uvOffset: number = 2;
  92. protected colorOffset: number = 4;
  93. protected colorExtraOffset: number = 5;
  94. protected textureIdxOffset: number = 6;
  95. protected _renderData = null;
  96. protected _local = [];
  97. protected get verticesFloats() { return this.verticesCount * this.floatsPerVert; }
  98. /** 每个字符的渲染数据 */
  99. private _lettersInfo: LetterInfo[] = [];
  100. constructor() {
  101. super();
  102. this._renderData = new cc["RenderData"]();
  103. this._renderData.init(this);
  104. this.initData();
  105. this.initLocal();
  106. }
  107. public initData(): void {
  108. let data = this._renderData;
  109. // createFlexData支持创建指定格式的renderData
  110. data.createFlexData(0, this.verticesCount, this.indicesCount, this.getVfmt());
  111. // createFlexData不会填充顶点索引信息,手动补充一下
  112. let indices = data.iDatas[0];
  113. let count = indices.length / 6;
  114. for (let i = 0, idx = 0; i < count; i++) {
  115. let vertextID = i * 4;
  116. indices[idx++] = vertextID;
  117. indices[idx++] = vertextID + 1;
  118. indices[idx++] = vertextID + 2;
  119. indices[idx++] = vertextID + 1;
  120. indices[idx++] = vertextID + 3;
  121. indices[idx++] = vertextID + 2;
  122. }
  123. }
  124. public initLocal(): void {
  125. this._local = [];
  126. this._local.length = 4;
  127. }
  128. public getBuffer(v) {
  129. return cc.renderer["_handle"].getBuffer("mesh", this.getVfmt());
  130. }
  131. public getVfmt() {
  132. return vfmt;
  133. }
  134. public fillBuffers(comp, renderer): void {
  135. if (renderer.worldMatDirty) {
  136. this.updateWorldVerts(comp);
  137. }
  138. let renderData = this._renderData;
  139. let vData = renderData.vDatas[0];
  140. let iData = renderData.iDatas[0];
  141. let buffer = this.getBuffer(renderer);
  142. let offsetInfo = buffer.request(this.verticesCount, this.indicesCount);
  143. // buffer data may be realloc, need get reference after request.
  144. // fill vertices
  145. let vertexOffset = offsetInfo.byteOffset >> 2,
  146. vbuf = buffer._vData;
  147. if (vData.length + vertexOffset > vbuf.length) {
  148. vbuf.set(vData.subarray(0, vbuf.length - vertexOffset), vertexOffset);
  149. } else {
  150. vbuf.set(vData, vertexOffset);
  151. }
  152. // fill indices
  153. let ibuf = buffer._iData,
  154. indiceOffset = offsetInfo.indiceOffset,
  155. vertexId = offsetInfo.vertexOffset;
  156. for (let i = 0, l = iData.length; i < l; i++) {
  157. ibuf[indiceOffset++] = vertexId + iData[i];
  158. }
  159. }
  160. /**
  161. * 执行一次渲染数据更新
  162. */
  163. public updateRenderData(comp: TextMeshPro): void {
  164. if (!comp["_vertsDirty"]) { return; }
  165. if (_comp === comp) { return; }
  166. if (!comp.fontConfig) { return; }
  167. _comp = comp;
  168. this._lettersInfo.length = 0;
  169. this._updateProperties(comp);
  170. this._updateContent();
  171. this.updateWorldVerts(comp);
  172. _comp["_actualFontSize"] = _fontSize;
  173. _comp.node.setContentSize(_contentSize);
  174. _comp["_vertsDirty"] = false;
  175. _comp = null;
  176. this._resetProperties();
  177. }
  178. /**
  179. * 更新渲染所需的前置数据
  180. */
  181. private _updateProperties(comp: TextMeshPro): void {
  182. _fntConfig = comp.fontConfig;
  183. _string = comp.string.toString();
  184. _fontSize = comp.fontSize;
  185. _originFontSize = _fntConfig ? _fntConfig.json.size : comp.fontSize;
  186. _bmfontScale = _fontSize / _originFontSize;
  187. _hAlign = comp.horizontalAlign;
  188. _vAlign = comp.verticalAlign;
  189. _spacingX = comp.spacingX;
  190. _overflow = comp.overflow;
  191. _lineHeight = comp.lineHeight;
  192. _contentSize.width = comp.node.width;
  193. _contentSize.height = comp.node.height;
  194. shareLabelInfo.fontAtlas = comp.fontConfig;
  195. shareLabelInfo.lineHeight = _lineHeight;
  196. shareLabelInfo.fontSize = _fontSize;
  197. shareLabelInfo.hash = "";
  198. shareLabelInfo.margin = 0;
  199. // should wrap text
  200. if (_overflow === TmpOverflow.NONE) {
  201. _isWrapText = false;
  202. _contentSize.width += shareLabelInfo.margin * 2;
  203. _contentSize.height += shareLabelInfo.margin * 2;
  204. } else if (_overflow === TmpOverflow.RESIZE_HEIGHT) {
  205. _isWrapText = true;
  206. _contentSize.height += shareLabelInfo.margin * 2;
  207. } else if (_overflow === TmpOverflow.SHRINK) {
  208. _isWrapText = false;
  209. } else {
  210. _isWrapText = comp.enableWrapText;
  211. }
  212. this._setupBMFontOverflowMetrics();
  213. // 斜体计算
  214. if (comp.enableItalic) {
  215. _italicVec.x = 0;
  216. _italicVec.y = _contentSize.height / 2;
  217. _italicVec.rotateSelf(ITALIC_REDIANS);
  218. _contentSize.width += Math.abs(_italicVec.x) * 2;
  219. _contentSize.height -= Math.abs(_contentSize.height / 2 - _italicVec.y) * 2;
  220. }
  221. // 下划线、删除线
  222. if (comp.enableUnderline || comp.enableStrikethrough) {
  223. _extraLineDef = shareLabelInfo.fontAtlas.getLetter(UNDERLINE_CODE + shareLabelInfo.hash);
  224. if (!_extraLineDef) {
  225. cc.log(`Can't find letter definition in textures. letter: _`);
  226. }
  227. }
  228. // 省略号
  229. if (comp.overflow === TmpOverflow.ELLIPSIS) {
  230. _ellipsisDef = shareLabelInfo.fontAtlas.getLetter(ELLIPSIS_CODE + shareLabelInfo.hash);
  231. if (_ellipsisDef) {
  232. _ellipsisWidth = (_ellipsisDef.xAdvance * _bmfontScale + _spacingX) * ELLIPSIS_NUM;
  233. } else {
  234. _ellipsisWidth = 0;
  235. cc.log(`Can't find letter definition in textures. letter: ${ELLIPSIS_CHAR}`);
  236. }
  237. }
  238. }
  239. private _resetProperties(): void {
  240. _fntConfig = null;
  241. shareLabelInfo.hash = "";
  242. shareLabelInfo.margin = 0;
  243. }
  244. private _updateContent(): void {
  245. this._computeHorizontalKerningForText();
  246. this._alignText();
  247. }
  248. private _computeHorizontalKerningForText(): void {
  249. let string = _string;
  250. let stringLen = string.length;
  251. let horizontalKernings = _horizontalKernings;
  252. let kerningDict;
  253. // _fntConfig && (kerningDict = _fntConfig.kerningDict);
  254. // if (kerningDict && !cc.js.isEmptyObject(kerningDict)) {
  255. // let prev = -1;
  256. // for (let i = 0; i < stringLen; ++i) {
  257. // let key = string.charCodeAt(i);
  258. // let kerningAmount = kerningDict[(prev << 16) | (key & 0xffff)] || 0;
  259. // if (i < stringLen - 1) {
  260. // horizontalKernings[i] = kerningAmount;
  261. // } else {
  262. // horizontalKernings[i] = 0;
  263. // }
  264. // prev = key;
  265. // }
  266. // } else {
  267. horizontalKernings.length = 0;
  268. // }
  269. }
  270. private _alignText(): void {
  271. _textDesiredHeight = 0;
  272. _linesWidth.length = 0;
  273. _extraLinesData = {};
  274. if (!_lineBreakWithoutSpaces) {
  275. this._multilineTextWrapByWord();
  276. } else {
  277. this._multilineTextWrapByChar();
  278. }
  279. // shrink
  280. if (_overflow === TmpOverflow.SHRINK && _fontSize > 0) {
  281. let scaleHeight = _bmfontScale;
  282. let scaleWidth = _bmfontScale;
  283. let needReset = false;
  284. if (_textDesiredHeight > _contentSize.height) {
  285. scaleHeight = (_contentSize.height / _textDesiredHeight) * _bmfontScale;
  286. needReset = true;
  287. }
  288. let maxWidth = 0;
  289. _linesWidth.forEach((v) => {
  290. if (v > maxWidth) {
  291. maxWidth = v;
  292. }
  293. });
  294. if (maxWidth > _contentSize.width) {
  295. scaleWidth = (_contentSize.width / maxWidth) * _bmfontScale;
  296. needReset = true;
  297. }
  298. _bmfontScale = Math.min(scaleHeight, scaleWidth);
  299. if (needReset) {
  300. _fontSize = _bmfontScale * _originFontSize;
  301. _textDesiredHeight = 0;
  302. _linesWidth.length = 0;
  303. _extraLinesData = {};
  304. if (!_lineBreakWithoutSpaces) {
  305. this._multilineTextWrapByWord();
  306. } else {
  307. this._multilineTextWrapByChar();
  308. }
  309. }
  310. }
  311. this._computeAlignmentOffset();
  312. // 顶点数据填充
  313. this._reserveQuads(_comp, this._lettersInfo.length);
  314. this._updateQuads();
  315. }
  316. private _multilineTextWrapByWord(): boolean {
  317. return this._multilineTextWrap(this._getFirstWordLen);
  318. }
  319. private _multilineTextWrapByChar(): boolean {
  320. return this._multilineTextWrap(this._getFirstCharLen);
  321. }
  322. private _multilineTextWrap(nextTokenFunc: Function): boolean {
  323. // 省略号处理
  324. let ellipsisMaxLines = 0;
  325. let useEllipsis = false;
  326. if (_overflow === TmpOverflow.ELLIPSIS && _ellipsisDef) {
  327. ellipsisMaxLines = Math.max(1, Math.floor(_contentSize.height / _lineHeight));
  328. }
  329. let textLen = _string.length;
  330. let lineIndex = 0;
  331. let nextTokenX = 0;
  332. let nextTokenY = 0;
  333. let longestLine = 0;
  334. let letterRight = 0;
  335. let highestY = 0;
  336. let lowestY = 0;
  337. let letterDef: TmpFontLetter = null;
  338. let letterPosition = cc.v2(0, 0);
  339. for (let index = 0; index < textLen;) {
  340. let character = _string.charAt(index);
  341. if (character === "\n") {
  342. // 省略号处理
  343. if (_overflow === TmpOverflow.ELLIPSIS && _ellipsisDef && lineIndex + 1 >= ellipsisMaxLines) {
  344. this._recordEllipsis(nextTokenY, letterPosition, lineIndex);
  345. useEllipsis = true;
  346. // 更新_linesWidth
  347. let ellipsisInfo = this._lettersInfo[this._lettersInfo.length - 1];
  348. // letterRight = ellipsisInfo.x + _ellipsisDef.w * _bmfontScale - shareLabelInfo.margin;
  349. letterRight = ellipsisInfo.x + (_ellipsisDef.xAdvance - _ellipsisDef.offsetX) * _bmfontScale + _spacingX - shareLabelInfo.margin * 2;
  350. break;
  351. }
  352. _linesWidth.push(letterRight);
  353. letterRight = 0;
  354. lineIndex++;
  355. nextTokenX = 0;
  356. nextTokenY -= _lineHeight * this._getFontScale() + _lineSpacing;
  357. this._recordPlaceholderInfo(index, character);
  358. index++;
  359. continue;
  360. }
  361. let tokenLen = nextTokenFunc(_string, index, textLen);
  362. let tokenHighestY = highestY;
  363. let tokenLowestY = lowestY;
  364. let tokenRight = letterRight;
  365. let nextLetterX = nextTokenX;
  366. let newLine = false;
  367. for (let tmp = 0; tmp < tokenLen; ++tmp) {
  368. let letterIndex = index + tmp;
  369. character = _string.charAt(letterIndex);
  370. if (character === "\r") {
  371. this._recordPlaceholderInfo(letterIndex, character);
  372. continue;
  373. }
  374. letterDef = shareLabelInfo.fontAtlas.getLetterDefinitionForChar(character);
  375. if (!letterDef) {
  376. this._recordPlaceholderInfo(letterIndex, character);
  377. cc.log(`Can't find letter definition in textures. letter: ${character}`);
  378. continue;
  379. }
  380. let letterX = nextLetterX + letterDef.offsetX * _bmfontScale - shareLabelInfo.margin;
  381. // 斜边处理
  382. if ((_comp as TextMeshPro).enableItalic) {
  383. _italicVec.x = 0;
  384. _italicVec.y = letterDef.h * _bmfontScale / 2;
  385. _italicVec.rotateSelf(ITALIC_REDIANS);
  386. letterX += Math.abs(_italicVec.x);
  387. }
  388. // 省略号处理
  389. if (_overflow === TmpOverflow.ELLIPSIS && _ellipsisDef) {
  390. if (letterX + (letterDef.xAdvance - letterDef.offsetX) * _bmfontScale > _maxLineWidth) {
  391. if (!_isWrapText || lineIndex + 1 >= ellipsisMaxLines) {
  392. this._recordEllipsis(nextTokenY, letterPosition, lineIndex);
  393. useEllipsis = true;
  394. // 更新_linesWidth
  395. let ellipsisInfo = this._lettersInfo[this._lettersInfo.length - 1];
  396. // letterRight = ellipsisInfo.x + _ellipsisDef.w * _bmfontScale - shareLabelInfo.margin;
  397. letterRight = ellipsisInfo.x + (_ellipsisDef.xAdvance - _ellipsisDef.offsetX) * _bmfontScale + _spacingX - shareLabelInfo.margin * 2;
  398. break;
  399. }
  400. }
  401. }
  402. if (_isWrapText
  403. && _maxLineWidth > 0
  404. && nextTokenX > 0
  405. && letterX + (letterDef.xAdvance - letterDef.offsetX) * _bmfontScale > _maxLineWidth
  406. && !cc["textUtils"].isUnicodeSpace(character)) {
  407. _linesWidth.push(letterRight);
  408. letterRight = 0;
  409. lineIndex++;
  410. nextTokenX = 0;
  411. nextTokenY -= (_lineHeight * this._getFontScale() + _lineSpacing);
  412. newLine = true;
  413. break;
  414. } else {
  415. letterPosition.x = letterX;
  416. }
  417. letterPosition.y = nextTokenY - letterDef.offsetY * _bmfontScale + shareLabelInfo.margin;
  418. this._recordLetterInfo(letterPosition, character, letterIndex, lineIndex);
  419. if (letterIndex + 1 < _horizontalKernings.length && letterIndex < textLen - 1) {
  420. nextLetterX += _horizontalKernings[letterIndex + 1];
  421. }
  422. nextLetterX += letterDef.xAdvance * _bmfontScale + _spacingX - shareLabelInfo.margin * 2;
  423. // tokenRight = letterPosition.x + letterDef.w * _bmfontScale - shareLabelInfo.margin;
  424. tokenRight = nextLetterX;
  425. // 斜边处理
  426. if ((_comp as TextMeshPro).enableItalic) {
  427. _italicVec.x = 0;
  428. _italicVec.y = letterDef.h * _bmfontScale / 2;
  429. _italicVec.rotateSelf(ITALIC_REDIANS);
  430. tokenRight += Math.abs(_italicVec.x);
  431. }
  432. if (tokenHighestY < letterPosition.y) {
  433. tokenHighestY = letterPosition.y;
  434. }
  435. if (tokenLowestY > letterPosition.y - letterDef.h * _bmfontScale) {
  436. tokenLowestY = letterPosition.y - letterDef.h * _bmfontScale;
  437. }
  438. } //end of for loop
  439. if (useEllipsis) { break; }
  440. if (newLine) { continue; }
  441. nextTokenX = nextLetterX;
  442. letterRight = tokenRight;
  443. if (highestY < tokenHighestY) {
  444. highestY = tokenHighestY;
  445. }
  446. if (lowestY > tokenLowestY) {
  447. lowestY = tokenLowestY;
  448. }
  449. if (longestLine < letterRight) {
  450. longestLine = letterRight;
  451. }
  452. index += tokenLen;
  453. } //end of for loop
  454. _linesWidth.push(letterRight);
  455. _numberOfLines = lineIndex + 1;
  456. _textDesiredHeight = _numberOfLines * _lineHeight * this._getFontScale();
  457. if (_numberOfLines > 1) {
  458. _textDesiredHeight += (_numberOfLines - 1) * _lineSpacing;
  459. }
  460. _contentSize.width = _labelWidth;
  461. _contentSize.height = _labelHeight;
  462. if (_labelWidth <= 0) {
  463. _contentSize.width = parseFloat(longestLine.toFixed(2)) + shareLabelInfo.margin * 2;
  464. }
  465. if (_labelHeight <= 0) {
  466. _contentSize.height = parseFloat(_textDesiredHeight.toFixed(2)) + shareLabelInfo.margin * 2;
  467. }
  468. _tailoredTopY = _contentSize.height;
  469. _tailoredBottomY = 0;
  470. if (_overflow !== TmpOverflow.CLAMP) {
  471. if (highestY > 0) {
  472. _tailoredTopY = _contentSize.height + highestY;
  473. }
  474. if (lowestY < -_textDesiredHeight) {
  475. _tailoredBottomY = _textDesiredHeight + lowestY;
  476. }
  477. }
  478. // 记录letterRight与nextTokenX的差值,供富文本排版使用
  479. _comp["_richTextDeltaX"] = nextTokenX - letterRight;
  480. return true;
  481. }
  482. private _getFirstCharLen(): number {
  483. return 1;
  484. }
  485. private _getFontScale(): number {
  486. return _overflow === TmpOverflow.SHRINK ? _bmfontScale : 1;
  487. }
  488. private _getFirstWordLen(text: string, startIndex: number, textLen: number): number {
  489. let character = text.charAt(startIndex);
  490. if (cc["textUtils"].isUnicodeCJK(character)
  491. || character === "\n"
  492. || cc["textUtils"].isUnicodeSpace(character)) {
  493. return 1;
  494. }
  495. let len = 1;
  496. let letterDef = shareLabelInfo.fontAtlas.getLetterDefinitionForChar(character);
  497. if (!letterDef) {
  498. return len;
  499. }
  500. let nextLetterX = letterDef.xAdvance * _bmfontScale + _spacingX;
  501. let letterX;
  502. for (let index = startIndex + 1; index < textLen; ++index) {
  503. character = text.charAt(index);
  504. letterDef = shareLabelInfo.fontAtlas.getLetterDefinitionForChar(character);
  505. if (!letterDef) {
  506. break;
  507. }
  508. letterX = nextLetterX + letterDef.offsetX * _bmfontScale;
  509. if (letterX + (letterDef.xAdvance - letterDef.offsetX) * _bmfontScale > _maxLineWidth
  510. && !cc["textUtils"].isUnicodeSpace(character)
  511. && _maxLineWidth > 0) {
  512. return len;
  513. }
  514. nextLetterX += letterDef.xAdvance * _bmfontScale + _spacingX;
  515. if (character === "\n"
  516. || cc["textUtils"].isUnicodeSpace(character)
  517. || cc["textUtils"].isUnicodeCJK(character)) {
  518. break;
  519. }
  520. len++;
  521. }
  522. return len;
  523. }
  524. /**
  525. * 从已记录的字符中倒退,直到能放下省略号
  526. */
  527. private _recordEllipsis(nextTokenY: number, letterPosition: cc.Vec2, lineIndex: number): void {
  528. let nextX = 0;
  529. let lastIndex = this._lettersInfo.length - 1;
  530. while (lastIndex >= 0) {
  531. let lastInfo = this._lettersInfo[lastIndex];
  532. let lastDef = shareLabelInfo.fontAtlas.getLetterDefinitionForChar(lastInfo.char);
  533. let lastW = lastDef ? lastDef.w : 0;
  534. let lastXAdvance = lastDef ? lastDef.xAdvance : 0;
  535. let lastOffsetX = lastDef ? lastDef.offsetX : 0;
  536. let lastRightX = lastInfo.x + lastW * _bmfontScale - shareLabelInfo.margin;
  537. nextX = lastInfo.x + (lastXAdvance - lastOffsetX) * _bmfontScale + _spacingX - shareLabelInfo.margin * 2;
  538. if (_maxLineWidth >= lastRightX + _ellipsisWidth) {
  539. break;
  540. }
  541. lastIndex--;
  542. this._lettersInfo.pop();
  543. }
  544. if (lastIndex < 0) {
  545. nextX = 0;
  546. }
  547. // 记录省略号
  548. letterPosition.y = nextTokenY - _ellipsisDef.offsetY * _bmfontScale + shareLabelInfo.margin;
  549. for (let i = 1; i <= ELLIPSIS_NUM; i++) {
  550. letterPosition.x = nextX + _ellipsisDef.offsetX * _bmfontScale - shareLabelInfo.margin;
  551. this._recordLetterInfo(letterPosition, ELLIPSIS_CHAR, lastIndex + i, lineIndex);
  552. nextX += _ellipsisDef.xAdvance * _bmfontScale + _spacingX - shareLabelInfo.margin * 2;
  553. }
  554. }
  555. /**
  556. * 记录无需渲染的占位符
  557. */
  558. private _recordPlaceholderInfo(letterIndex: number, char: string): void {
  559. if (letterIndex >= this._lettersInfo.length) {
  560. let tmpInfo = new LetterInfo();
  561. this._lettersInfo.push(tmpInfo);
  562. }
  563. this._lettersInfo[letterIndex].char = char;
  564. this._lettersInfo[letterIndex].hash = char.charCodeAt(0) + shareLabelInfo.hash;
  565. this._lettersInfo[letterIndex].valid = false;
  566. }
  567. /**
  568. * 记录需要渲染的字符
  569. */
  570. private _recordLetterInfo(letterPosition: cc.Vec2, character: string, letterIndex: number, lineIndex: number): void {
  571. if (letterIndex >= this._lettersInfo.length) {
  572. let tmpInfo = new LetterInfo();
  573. this._lettersInfo.push(tmpInfo);
  574. }
  575. let char = character.charCodeAt(0);
  576. let key = char + shareLabelInfo.hash;
  577. this._lettersInfo[letterIndex].line = lineIndex;
  578. this._lettersInfo[letterIndex].char = character;
  579. this._lettersInfo[letterIndex].hash = key;
  580. this._lettersInfo[letterIndex].valid = shareLabelInfo.fontAtlas.getLetter(key).valid;
  581. this._lettersInfo[letterIndex].x = letterPosition.x;
  582. this._lettersInfo[letterIndex].y = letterPosition.y;
  583. }
  584. private _computeAlignmentOffset(): void {
  585. _linesOffsetX.length = 0;
  586. switch (_hAlign) {
  587. case cc.Label.HorizontalAlign.LEFT:
  588. for (let i = 0; i < _numberOfLines; ++i) {
  589. _linesOffsetX.push(0);
  590. }
  591. break;
  592. case cc.Label.HorizontalAlign.CENTER:
  593. for (let i = 0, l = _linesWidth.length; i < l; i++) {
  594. _linesOffsetX.push((_contentSize.width - _linesWidth[i]) / 2);
  595. }
  596. break;
  597. case cc.Label.HorizontalAlign.RIGHT:
  598. for (let i = 0, l = _linesWidth.length; i < l; i++) {
  599. _linesOffsetX.push(_contentSize.width - _linesWidth[i]);
  600. }
  601. break;
  602. default:
  603. break;
  604. }
  605. // TOP
  606. _letterOffsetY = _contentSize.height;
  607. if (_vAlign !== cc.Label.VerticalAlign.TOP) {
  608. let blank = _contentSize.height - _textDesiredHeight + _lineHeight * this._getFontScale() - _originFontSize * _bmfontScale;
  609. if (_vAlign === cc.Label.VerticalAlign.BOTTOM) {
  610. // BOTTOM
  611. _letterOffsetY -= blank;
  612. } else {
  613. // CENTER:
  614. _letterOffsetY -= blank / 2;
  615. }
  616. }
  617. }
  618. private _setupBMFontOverflowMetrics(): void {
  619. let newWidth = _contentSize.width;
  620. let newHeight = _contentSize.height;
  621. if (_overflow === TmpOverflow.RESIZE_HEIGHT) {
  622. newHeight = 0;
  623. }
  624. if (_overflow === TmpOverflow.NONE) {
  625. newWidth = 0;
  626. newHeight = 0;
  627. }
  628. _labelWidth = newWidth;
  629. _labelHeight = newHeight;
  630. _maxLineWidth = newWidth;
  631. }
  632. /**
  633. * 更新所有顶点数据
  634. */
  635. private _updateQuads(): void {
  636. let node = _comp.node;
  637. this.verticesCount = this.indicesCount = 0;
  638. // Need to reset dataLength in Canvas rendering mode.
  639. this._renderData && (this._renderData.dataLength = 0);
  640. let contentSize = _contentSize,
  641. appx = node["_anchorPoint"].x * contentSize.width,
  642. appy = node["_anchorPoint"].y * contentSize.height;
  643. let quadsIndex = 0;
  644. for (let i = 0, l = this._lettersInfo.length; i < l; ++i) {
  645. let letterInfo = this._lettersInfo[i];
  646. if (!letterInfo) break;
  647. if (!letterInfo.valid) continue;
  648. letterInfo.quadsIndex = quadsIndex;
  649. let letterDef = shareLabelInfo.fontAtlas.getLetter(letterInfo.hash);
  650. _tmpUvRect.height = letterDef.h;
  651. _tmpUvRect.width = letterDef.w;
  652. _tmpUvRect.x = letterDef.u;
  653. _tmpUvRect.y = letterDef.v;
  654. let py = letterInfo.y + _letterOffsetY;
  655. if (_labelHeight > 0) {
  656. if (_overflow === TmpOverflow.CLAMP) {
  657. if (py > _tailoredTopY) {
  658. let clipTop = py - _tailoredTopY;
  659. _tmpUvRect.y += clipTop / _bmfontScale;
  660. _tmpUvRect.height -= clipTop / _bmfontScale;
  661. py = py - clipTop;
  662. }
  663. if ((py - _tmpUvRect.height * _bmfontScale < _tailoredBottomY)) {
  664. _tmpUvRect.height = (py < _tailoredBottomY) ? 0 : (py - _tailoredBottomY) / _bmfontScale;
  665. }
  666. }
  667. }
  668. let px = letterInfo.x + _linesOffsetX[letterInfo.line];
  669. if (_labelWidth > 0) {
  670. if (_overflow === TmpOverflow.CLAMP) {
  671. if (px < 0) {
  672. _tmpUvRect.x += -px / _bmfontScale;
  673. _tmpUvRect.width -= -px / _bmfontScale;
  674. px = 0;
  675. }
  676. if (px + _tmpUvRect.width * _bmfontScale > _contentSize.width) {
  677. let clipRight = px + _tmpUvRect.width * _bmfontScale - _contentSize.width;
  678. _tmpUvRect.width -= clipRight / _bmfontScale;
  679. }
  680. }
  681. }
  682. if (_tmpUvRect.height > 0 && _tmpUvRect.width > 0) {
  683. _tmpPosRect.x = px - appx;
  684. _tmpPosRect.y = py - appy;
  685. _tmpPosRect.width = _tmpUvRect.width * _bmfontScale;
  686. _tmpPosRect.height = _tmpUvRect.height * _bmfontScale;
  687. this.appendQuad(letterDef.textureId, _tmpUvRect, _tmpPosRect);
  688. quadsIndex++;
  689. // 下划线数据记录
  690. if (_extraLineDef && ((_comp as TextMeshPro).enableUnderline || (_comp as TextMeshPro).enableStrikethrough)) {
  691. if (!cc["textUtils"].isUnicodeSpace(letterInfo.char)) {
  692. let lineData = _extraLinesData[letterInfo.line];
  693. if (!lineData) {
  694. _extraLinesData[letterInfo.line] = {
  695. lineIndex: letterInfo.line,
  696. first: i,
  697. last: i
  698. }
  699. } else {
  700. if (lineData.last < i) {
  701. lineData.last = i;
  702. }
  703. }
  704. }
  705. }
  706. }
  707. }
  708. if (_extraLineDef) {
  709. // 下划线
  710. if ((_comp as TextMeshPro).enableUnderline) {
  711. this._updateLineQuads(appx, appy, -_fontSize + (_comp as TextMeshPro).underlineOffset * _bmfontScale);
  712. }
  713. // 删除线
  714. if ((_comp as TextMeshPro).enableStrikethrough) {
  715. this._updateLineQuads(appx, appy, -_fontSize / 2 + (_comp as TextMeshPro).strikethroughOffset * _bmfontScale);
  716. }
  717. }
  718. this.updateColorExtra(_comp);
  719. this._quadsUpdated();
  720. }
  721. /**
  722. * 更新下划线、删除线的顶点数据
  723. */
  724. private _updateLineQuads(appx: number, appy: number, offsetY: number): void {
  725. for (let key in _extraLinesData) {
  726. let underlineInfo = _extraLinesData[key];
  727. let lineIdx = underlineInfo.lineIndex;
  728. let first = underlineInfo.first;
  729. let last = underlineInfo.last > 0 ? underlineInfo.last : first;
  730. let firstInfo = this._lettersInfo[first];
  731. if (!firstInfo.valid) {
  732. continue;
  733. }
  734. let lastInfo = this._lettersInfo[last];
  735. let firstDef = shareLabelInfo.fontAtlas.getLetter(firstInfo.hash);
  736. let lastDef = shareLabelInfo.fontAtlas.getLetter(lastInfo.hash);
  737. let maxWidth = lastInfo.x + lastDef.w * _bmfontScale - firstInfo.x;
  738. let wLeft = maxWidth >= _extraLineDef.w * _bmfontScale ? _extraLineDef.w * _bmfontScale / 3 : maxWidth / 2;
  739. let wRight = wLeft;
  740. let wMid = maxWidth - wLeft - wRight;
  741. let leftX = firstInfo.x + _linesOffsetX[lineIdx];
  742. let rightX = leftX + wLeft + wMid;
  743. let midX = leftX + wLeft;
  744. // 左
  745. _tmpUvRect.height = _extraLineDef.h;
  746. _tmpUvRect.width = wLeft / _bmfontScale;
  747. _tmpUvRect.x = _extraLineDef.u;
  748. _tmpUvRect.y = _extraLineDef.v;
  749. let py = firstInfo.y + _letterOffsetY + firstDef.offsetY * _bmfontScale + offsetY;
  750. if (_labelHeight > 0) {
  751. if (py > _tailoredTopY) {
  752. let clipTop = py - _tailoredTopY;
  753. _tmpUvRect.y += clipTop;
  754. _tmpUvRect.height -= clipTop;
  755. py = py - clipTop;
  756. }
  757. if ((py - _extraLineDef.h * _bmfontScale < _tailoredBottomY) && _overflow === TmpOverflow.CLAMP) {
  758. _tmpUvRect.height = (py < _tailoredBottomY) ? 0 : (py - _tailoredBottomY) / _bmfontScale;
  759. }
  760. }
  761. if (_tmpUvRect.height > 0 && _tmpUvRect.width > 0) {
  762. _tmpPosRect.x = leftX - appx;
  763. _tmpPosRect.y = py - appy;
  764. _tmpPosRect.width = wLeft;
  765. _tmpPosRect.height = _tmpUvRect.height * _bmfontScale;
  766. this.appendQuad(_extraLineDef.textureId, _tmpUvRect, _tmpPosRect);
  767. }
  768. // 右
  769. _tmpUvRect.width = wRight / _bmfontScale;
  770. _tmpUvRect.x = _extraLineDef.u + _extraLineDef.w - _tmpUvRect.width;
  771. if (_tmpUvRect.height > 0 && _tmpUvRect.width > 0) {
  772. _tmpPosRect.x = rightX - appx;
  773. _tmpPosRect.y = py - appy;
  774. _tmpPosRect.width = wRight;
  775. _tmpPosRect.height = _tmpUvRect.height * _bmfontScale;
  776. this.appendQuad(_extraLineDef.textureId, _tmpUvRect, _tmpPosRect);
  777. }
  778. // 中
  779. if (wMid > 0) {
  780. _tmpUvRect.width = _extraLineDef.w - wLeft * 2 / _bmfontScale;
  781. _tmpUvRect.x = _extraLineDef.u + _tmpUvRect.width;
  782. if (_tmpUvRect.height > 0 && _tmpUvRect.width > 0) {
  783. _tmpPosRect.x = midX - appx;
  784. _tmpPosRect.y = py - appy;
  785. _tmpPosRect.width = wMid;
  786. _tmpPosRect.height = _tmpUvRect.height * _bmfontScale;
  787. this.appendQuad(_extraLineDef.textureId, _tmpUvRect, _tmpPosRect);
  788. }
  789. }
  790. }
  791. }
  792. /**
  793. * 顶点数据、索引数据初始化
  794. */
  795. private _reserveQuads(comp: TextMeshPro, count: number): void {
  796. let extra = 0;
  797. if (comp.enableUnderline) {
  798. extra++;
  799. }
  800. if (comp.enableStrikethrough) {
  801. extra++;
  802. }
  803. count = count + extra * _numberOfLines * 3;
  804. let verticesCount = count * 4;
  805. let indicesCount = count * 6;
  806. let flexBuffer = this._renderData._flexBuffer;
  807. flexBuffer.reserve(verticesCount, indicesCount);
  808. flexBuffer.used(verticesCount, indicesCount);
  809. let iData = this._renderData.iDatas[0];
  810. for (let i = 0, vid = 0, l = indicesCount; i < l; i += 6, vid += 4) {
  811. iData[i] = vid;
  812. iData[i + 1] = vid + 1;
  813. iData[i + 2] = vid + 2;
  814. iData[i + 3] = vid + 1;
  815. iData[i + 4] = vid + 3;
  816. iData[i + 5] = vid + 2;
  817. }
  818. _dataOffset = 0;
  819. }
  820. /**
  821. * 更新实际使用的顶点数据、索引数据长度
  822. */
  823. private _quadsUpdated(): void {
  824. _dataOffset = 0;
  825. let flexBuffer = this._renderData._flexBuffer;
  826. flexBuffer.used(this.verticesCount, this.indicesCount);
  827. }
  828. /**
  829. * 添加一组顶点数据(4个顶点)
  830. * @param textureId 渲染的字符所需纹理id
  831. * @param uvRect 顶点uv数据
  832. * @param posRect 顶点坐标数据
  833. */
  834. private appendQuad(textureId: number, uvRect: cc.Rect, posRect: cc.Rect): void {
  835. let renderData = this._renderData;
  836. let verts = renderData.vDatas[0],
  837. uintVerts = renderData.uintVDatas[0];
  838. this.verticesCount += 4;
  839. this.indicesCount = this.verticesCount / 2 * 3;
  840. let texture = shareLabelInfo.fontAtlas.getTexture(textureId);
  841. let texw = texture.width,
  842. texh = texture.height,
  843. rectWidth = uvRect.width,
  844. rectHeight = uvRect.height,
  845. color = _comp.node["_color"]._val;
  846. let l, b, r, t;
  847. let floatsPerVert = this.floatsPerVert;
  848. // uvs
  849. let uvDataOffset = _dataOffset + this.uvOffset;
  850. l = (uvRect.x) / texw;
  851. r = (uvRect.x + rectWidth) / texw;
  852. b = (uvRect.y + rectHeight) / texh;
  853. t = (uvRect.y) / texh;
  854. verts[uvDataOffset] = l;
  855. verts[uvDataOffset + 1] = b;
  856. uvDataOffset += floatsPerVert;
  857. verts[uvDataOffset] = r;
  858. verts[uvDataOffset + 1] = b;
  859. uvDataOffset += floatsPerVert;
  860. verts[uvDataOffset] = l;
  861. verts[uvDataOffset + 1] = t;
  862. uvDataOffset += floatsPerVert;
  863. verts[uvDataOffset] = r;
  864. verts[uvDataOffset + 1] = t;
  865. // positions
  866. l = posRect.x;
  867. r = posRect.x + posRect.width;
  868. b = posRect.y - posRect.height;
  869. t = posRect.y;
  870. this.appendVerts(_comp, _dataOffset, l, r, b, t);
  871. // colors
  872. let colorOffset = _dataOffset + this.colorOffset;
  873. for (let i = 0; i < 4; i++) {
  874. uintVerts[colorOffset] = color;
  875. colorOffset += floatsPerVert;
  876. }
  877. // colorExtra
  878. let colorExtraOffset = _dataOffset + this.colorExtraOffset;
  879. for (let i = 0; i < 4; i++) {
  880. uintVerts[colorExtraOffset] = WHITE["_val"];
  881. colorExtraOffset += floatsPerVert;
  882. }
  883. // textureId
  884. let idOffset = _dataOffset + this.textureIdxOffset;
  885. for (let i = 0; i < 4; i++) {
  886. verts[idOffset] = textureId;
  887. idOffset += this.floatsPerVert;
  888. }
  889. _dataOffset += this.floatsPerVert * 4;
  890. }
  891. private appendVerts(comp: TextMeshPro, offset, l, r, b, t): void {
  892. let local = this._local;
  893. let floatsPerVert = this.floatsPerVert;
  894. if (comp.enableItalic) {
  895. _italicVec.x = 0;
  896. _italicVec.y = (t - b) / 2;
  897. _italicVec.rotateSelf(ITALIC_REDIANS);
  898. local[offset] = l - Math.abs(_italicVec.x);
  899. local[offset + 1] = b + Math.abs((t - b) / 2 - _italicVec.y);
  900. offset += floatsPerVert;
  901. local[offset] = r - Math.abs(_italicVec.x);
  902. local[offset + 1] = b + Math.abs((t - b) / 2 - _italicVec.y);
  903. offset += floatsPerVert;
  904. local[offset] = l + Math.abs(_italicVec.x);
  905. local[offset + 1] = t - Math.abs((t - b) / 2 - _italicVec.y);
  906. offset += floatsPerVert;
  907. local[offset] = r + Math.abs(_italicVec.x);
  908. local[offset + 1] = t - Math.abs((t - b) / 2 - _italicVec.y);
  909. } else {
  910. local[offset] = l;
  911. local[offset + 1] = b;
  912. offset += floatsPerVert;
  913. local[offset] = r;
  914. local[offset + 1] = b;
  915. offset += floatsPerVert;
  916. local[offset] = l;
  917. local[offset + 1] = t;
  918. offset += floatsPerVert;
  919. local[offset] = r;
  920. local[offset + 1] = t;
  921. }
  922. }
  923. /**
  924. * 更新顶点世界坐标数据
  925. */
  926. public updateWorldVerts(comp: TextMeshPro): void {
  927. let node = comp.node;
  928. let local = this._local;
  929. let world = this._renderData.vDatas[0];
  930. let floatsPerVert = this.floatsPerVert;
  931. if (CC_NATIVERENDERER) {
  932. for (let offset = 0, l = local.length; offset < l; offset += floatsPerVert) {
  933. world[offset] = local[offset];
  934. world[offset + 1] = local[offset + 1];
  935. }
  936. } else {
  937. let matrix = node["_worldMatrix"];
  938. let matrixm = matrix.m,
  939. a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
  940. tx = matrixm[12], ty = matrixm[13];
  941. for (let offset = 0; offset < local.length; offset += floatsPerVert) {
  942. let x = local[offset];
  943. let y = local[offset + 1];
  944. world[offset] = x * a + y * c + tx;
  945. world[offset + 1] = x * b + y * d + ty;
  946. }
  947. }
  948. }
  949. public updateColor(comp, color?): void {
  950. if (CC_NATIVERENDERER) {
  951. this["_dirtyPtr"][0] |= cc["Assembler"]["FLAG_VERTICES_OPACITY_CHANGED"];
  952. }
  953. let uintVerts = this._renderData.uintVDatas[0];
  954. if (!uintVerts) return;
  955. color = color != null ? color : comp.node.color._val;
  956. let floatsPerVert = this.floatsPerVert;
  957. let colorOffset = this.colorOffset;
  958. for (let i = colorOffset, l = uintVerts.length; i < l; i += floatsPerVert) {
  959. uintVerts[i] = color;
  960. }
  961. }
  962. /**
  963. * 更新额外顶点颜色,不对下划线、删除线生效
  964. */
  965. public updateColorExtra(comp: TextMeshPro): void {
  966. let uintVerts = this._renderData.uintVDatas[0];
  967. if (!uintVerts) return;
  968. let tmpColor = cc.color();
  969. for (let i = 0; i < this._lettersInfo.length; i++) {
  970. let info = this._lettersInfo[i];
  971. if (!info.valid || cc["textUtils"].isUnicodeSpace(info.char)) {
  972. continue;
  973. }
  974. let alpha = info.visible ? 1 : 0;
  975. let offset = this.colorExtraOffset + this.floatsPerVert * info.quadsIndex * 4;
  976. tmpColor.set(WHITE);
  977. tmpColor.setA(tmpColor.a * alpha);
  978. comp.colorGradient && tmpColor.multiply(comp.colorLB);
  979. uintVerts[offset] = tmpColor["_val"];
  980. offset += this.floatsPerVert;
  981. tmpColor.set(WHITE);
  982. tmpColor.setA(tmpColor.a * alpha);
  983. comp.colorGradient && tmpColor.multiply(comp.colorRB);
  984. uintVerts[offset] = tmpColor["_val"];
  985. offset += this.floatsPerVert;
  986. tmpColor.set(WHITE);
  987. tmpColor.setA(tmpColor.a * alpha);
  988. comp.colorGradient && tmpColor.multiply(comp.colorLT);
  989. uintVerts[offset] = tmpColor["_val"];
  990. offset += this.floatsPerVert;
  991. tmpColor.set(WHITE);
  992. tmpColor.setA(tmpColor.a * alpha);
  993. comp.colorGradient && tmpColor.multiply(comp.colorRT);
  994. uintVerts[offset] = tmpColor["_val"];
  995. }
  996. }
  997. //#region 顶点数据操作接口
  998. /**
  999. * 根据字符下标判断此字符是否可见
  1000. */
  1001. public isVisble(index: number): boolean {
  1002. let info = this._lettersInfo[index];
  1003. return info && info.valid && info.visible && !cc["textUtils"].isUnicodeSpace(info.char);
  1004. }
  1005. /**
  1006. * 根据字符下标设置字符是否可见
  1007. */
  1008. public setVisible(comp: TextMeshPro, index: number, visible: boolean): void {
  1009. let info = this._lettersInfo[index];
  1010. if (!info || this.isVisble(index) === visible || info.visible === visible || cc["textUtils"].isUnicodeSpace(info.char)) {
  1011. return;
  1012. }
  1013. info.visible = visible;
  1014. let offset = this.colorExtraOffset + this.floatsPerVert * info.quadsIndex * 4;
  1015. let color = cc.color();
  1016. let alpha = (visible ? 1 : 0);
  1017. let uintVerts = this._renderData.uintVDatas[0];
  1018. color.set(WHITE);
  1019. color.setA(color.a * alpha);
  1020. comp.colorGradient && color.multiply(comp.colorLB);
  1021. uintVerts[offset] = color["_val"];
  1022. offset += this.floatsPerVert;
  1023. color.set(WHITE);
  1024. color.setA(color.a * alpha);
  1025. comp.colorGradient && color.multiply(comp.colorRB);
  1026. uintVerts[offset] = color["_val"];
  1027. offset += this.floatsPerVert;
  1028. color.set(WHITE);
  1029. color.setA(color.a * alpha);
  1030. comp.colorGradient && color.multiply(comp.colorLT);
  1031. uintVerts[offset] = color["_val"];
  1032. offset += this.floatsPerVert;
  1033. color.set(WHITE);
  1034. color.setA(color.a * alpha);
  1035. comp.colorGradient && color.multiply(comp.colorRT);
  1036. uintVerts[offset] = color["_val"];
  1037. }
  1038. /**
  1039. * 根据字符下标获取颜色顶点数据,顺序为[左下, 右下, 左上, 右上]
  1040. */
  1041. public getColorExtraVertices(index: number): [cc.Color, cc.Color, cc.Color, cc.Color] | null {
  1042. let info = this._lettersInfo[index];
  1043. if (!info || !info.valid) {
  1044. return null;
  1045. }
  1046. let result: [cc.Color, cc.Color, cc.Color, cc.Color] = [] as any;
  1047. let uintVerts = this._renderData.uintVDatas[0];
  1048. let offset = this.colorExtraOffset + this.floatsPerVert * info.quadsIndex * 4;
  1049. for (let i = 0; i < 4; i++) {
  1050. let color = cc.color();
  1051. color["_val"] = uintVerts[offset];
  1052. result.push(color);
  1053. offset += this.floatsPerVert;
  1054. }
  1055. return result;
  1056. }
  1057. /**
  1058. * 根据字符下标设置颜色顶点数据,顺序为[左下, 右下, 左上, 右上]
  1059. */
  1060. public setColorExtraVertices(index: number, data: [cc.Color, cc.Color, cc.Color, cc.Color]): void {
  1061. let info = this._lettersInfo[index];
  1062. if (!info || !info.valid || data.length !== 4 || cc["textUtils"].isUnicodeSpace(info.char)) {
  1063. return;
  1064. }
  1065. let uintVerts = this._renderData.uintVDatas[0];
  1066. let offset = this.colorExtraOffset + this.floatsPerVert * info.quadsIndex * 4;
  1067. for (let i = 0; i < 4; i++) {
  1068. uintVerts[offset] = data[i]["_val"];
  1069. offset += this.floatsPerVert;
  1070. }
  1071. }
  1072. /**
  1073. * 根据字符下标获取坐标顶点数据,顺序为[左下, 右下, 左上, 右上]
  1074. */
  1075. public getPosVertices(index: number): [cc.Vec2, cc.Vec2, cc.Vec2, cc.Vec2] | null {
  1076. let info = this._lettersInfo[index];
  1077. if (!info || !info.valid) {
  1078. return null;
  1079. }
  1080. let result: [cc.Vec2, cc.Vec2, cc.Vec2, cc.Vec2] = [] as any;
  1081. let local = this._local;
  1082. let offset = this.floatsPerVert * info.quadsIndex * 4;
  1083. for (let i = 0; i < 4; i++) {
  1084. result.push(cc.v2(local[offset], local[offset + 1]));
  1085. offset += this.floatsPerVert;
  1086. }
  1087. return result;
  1088. }
  1089. /**
  1090. * 根据字符下标设置坐标顶点数据,顺序为[左下, 右下, 左上, 右上]
  1091. */
  1092. public setPosVertices(index: number, data: [cc.Vec2, cc.Vec2, cc.Vec2, cc.Vec2]): void {
  1093. let info = this._lettersInfo[index];
  1094. if (!info || !info.valid || data.length !== 4 || cc["textUtils"].isUnicodeSpace(info.char)) {
  1095. return;
  1096. }
  1097. let local = this._local;
  1098. let offset = this.floatsPerVert * info.quadsIndex * 4;
  1099. for (let i = 0; i < 4; i++) {
  1100. local[offset] = data[i].x;
  1101. local[offset + 1] = data[i].y;
  1102. offset += this.floatsPerVert;
  1103. }
  1104. }
  1105. //#endregion
  1106. }