cocos-enhance-kit/patches/v1.0.0/0009-Char.patch
2022-06-22 00:58:14 +08:00

620 lines
20 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 29ab0105fffc4316b06eab3e4834e5675b730259 Mon Sep 17 00:00:00 2001
From: SmallMain <smallmain@outlook.com>
Date: Tue, 21 Jun 2022 11:55:32 +0800
Subject: [PATCH 09/16] =?UTF-8?q?=E6=96=B0=E7=9A=84=20Char=20=E7=BC=93?=
=?UTF-8?q?=E5=AD=98=E6=A8=A1=E5=BC=8F=E5=AE=9E=E7=8E=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
engine/cocos2d/core/asset-manager/builtins.js | 2 +-
engine/cocos2d/core/components/CCLabel.js | 4 +
.../core/renderer/utils/label/bmfont.js | 7 +-
.../core/renderer/utils/label/letter-font.js | 397 ++++++++++++++++--
.../webgl/assemblers/label/2d/bmfont.js | 6 +-
5 files changed, 366 insertions(+), 50 deletions(-)
diff --git a/engine/cocos2d/core/asset-manager/builtins.js b/engine/cocos2d/core/asset-manager/builtins.js
index ea87ebe..668ca0f 100644
--- a/engine/cocos2d/core/asset-manager/builtins.js
+++ b/engine/cocos2d/core/asset-manager/builtins.js
@@ -95,7 +95,7 @@ var builtins = {
effect.addRef();
cc.sp.inited = true;
cc.sp.multiBatcher.init();
- if (cc.dynamicAtlasManager.maxAtlasCount === -1) cc.dynamicAtlasManager.maxAtlasCount = cc.sp.MAX_MULTITEXTURE_NUM;
+ if (cc.dynamicAtlasManager.maxAtlasCount === -1) cc.dynamicAtlasManager.maxAtlasCount = Math.max(0, cc.sp.MAX_MULTITEXTURE_NUM - cc.sp.charAtlasAutoBatchCount);
cb();
});
},
diff --git a/engine/cocos2d/core/components/CCLabel.js b/engine/cocos2d/core/components/CCLabel.js
index d5116cc..b672f23 100644
--- a/engine/cocos2d/core/components/CCLabel.js
+++ b/engine/cocos2d/core/components/CCLabel.js
@@ -483,6 +483,10 @@ let Label = cc.Class({
if (oldValue === CacheMode.CHAR) {
this._ttfTexture = null;
+ const material = this._materials[0];
+ if (material && material.material && cc.Label._shareAtlas.material === material.material) {
+ this.setMaterial(0, this._getDefaultMaterial());
+ }
}
if (!this.enabledInHierarchy) return;
diff --git a/engine/cocos2d/core/renderer/utils/label/bmfont.js b/engine/cocos2d/core/renderer/utils/label/bmfont.js
index 9568825..900c08a 100644
--- a/engine/cocos2d/core/renderer/utils/label/bmfont.js
+++ b/engine/cocos2d/core/renderer/utils/label/bmfont.js
@@ -337,6 +337,8 @@ export default class BmfontAssembler extends Assembler2D {
index += tokenLen;
} //end of for loop
+ this._finishMultilineTextWrap();
+
_linesWidth.push(letterRight);
_numberOfLines = lineIndex + 1;
@@ -636,7 +638,7 @@ export default class BmfontAssembler extends Assembler2D {
if (_tmpRect.height > 0 && _tmpRect.width > 0) {
let isRotated = this._determineRect(_tmpRect);
let letterPositionX = letterInfo.x + _linesOffsetX[letterInfo.line];
- this.appendQuad(_comp, texture, _tmpRect, isRotated, letterPositionX - appx, py - appy, _bmfontScale);
+ this.appendQuad(_comp, texture, _tmpRect, isRotated, letterPositionX - appx, py - appy, _bmfontScale, letterDef);
}
}
this._quadsUpdated(_comp);
@@ -725,8 +727,9 @@ export default class BmfontAssembler extends Assembler2D {
updateWorldVerts() {}
- appendQuad (comp, texture, rect, rotated, x, y, scale) {}
+ appendQuad(comp, texture, rect, rotated, x, y, scale, letter) {}
_quadsUpdated (comp) {}
_reserveQuads () {}
+ _finishMultilineTextWrap() { }
}
diff --git a/engine/cocos2d/core/renderer/utils/label/letter-font.js b/engine/cocos2d/core/renderer/utils/label/letter-font.js
index 5e46af0..0e7aaae 100644
--- a/engine/cocos2d/core/renderer/utils/label/letter-font.js
+++ b/engine/cocos2d/core/renderer/utils/label/letter-font.js
@@ -24,6 +24,7 @@
****************************************************************************/
import WebglBmfontAssembler from '../../webgl/assemblers/label/2d/bmfont';
+import { vfmtPosUvColorTexId } from '../../webgl/vertex-format';
const Label = require('../../../components/CCLabel');
const LabelOutline = require('../../../components/CCLabelOutline');
@@ -125,29 +126,82 @@ LetterTexture.prototype = {
},
}
-function LetterAtlas (width, height) {
+function LetterAtlas(atlases, width, height) {
let texture = new RenderTexture();
texture.initWithSize(width, height);
texture.update();
- this._fontDefDictionary = new FontAtlas(texture);
-
+ this._atlases = atlases;
+ this._texture = texture;
+ this._id = 0;
+ this._tmpId = -1;
+
this._x = space;
this._y = space;
this._nexty = space;
+ this.frees = [];
+ this.waitCleans = [];
+
this._width = width;
this._height = height;
-
- cc.director.on(cc.Director.EVENT_BEFORE_SCENE_LAUNCH, this.beforeSceneLoad, this);
}
cc.js.mixin(LetterAtlas.prototype, {
- insertLetterTexture (letterTexture) {
+ insertLetterTexture(letterTexture) {
let texture = letterTexture._texture;
- let width = texture.width, height = texture.height;
+ let width = texture.width, height = texture.height;
+
+ // 先寻找是否有可用的被回收的区域
+ if (this.frees.length > 0) {
+ let score = Number.MAX_VALUE;
+ let areaFit = 0;
+ let original = null;
+ let originalIndex = 0;
+
+ for (let i = 0; i < this.frees.length; i++) {
+ const freeLetter = this.frees[i];
+ if (freeLetter._width === width && freeLetter._height === height) {
+ areaFit = freeLetter._width * freeLetter._height - width * height;
+ if (areaFit < score) {
+ original = freeLetter;
+ originalIndex = i;
+ score = areaFit;
+ }
+ }
+ }
+
+ if (original) {
+ original._hash = letterTexture._hash;
+ original.w = letterTexture._width - bleed;
+ original.h = letterTexture._height - bleed;
+ original.xAdvance = original.w;
+ original.offsetY = letterTexture._offsetY;
+
+ this._texture.drawTextureAt(texture, original.u - bleed / 2, original.v - bleed / 2);
+
+ this._dirty = true;
+
+ this.removeFreeLetter(originalIndex);
+
+ this._atlases._fontDefDictionary.addLetterDefinitions(letterTexture._hash, original);
+ return original;
+ }
+ }
+
+ // 有 bleed 问题,暂时不能复用不同高宽的空间
+ // 矫正宽度为三档: <0.75x height <1x height >1x height
+ // if (width <= height * 0.75) {
+ // width = height * 0.75;
+ // } else if (width <= height) {
+ // width = height;
+ // }
+
+ // 没有可用的被回收区域,尝试直接插入
+ const oldx = this._x, oldy = this._y, oldnexty = this._nexty;
if ((this._x + width + space) > this._width) {
+ // TODO 跳到下一行之前将这行的剩余区域切成多个正方形并放入 frees避免浪费
this._x = space;
this._y = this._nexty;
}
@@ -157,33 +211,69 @@ cc.js.mixin(LetterAtlas.prototype, {
}
if (this._nexty > this._height) {
- return null;
+ this._x = oldx;
+ this._y = oldy;
+ this._nexty = oldnexty;
+
+ // 回收 waitCleans
+ if (this.waitCleans.length > 0) {
+ for (const letter of this.waitCleans) {
+ letter._inCleans = false;
+ if (letter.ref === 0) {
+ delete this._atlases._fontDefDictionary._letterDefinitions[letter._hash];
+ this.frees.push(letter);
+ }
+ }
+ this.waitCleans.length = 0;
+ return this.insertLetterTexture(letterTexture);
+ } else {
+ return null;
+ }
}
- this._fontDefDictionary._texture.drawTextureAt(texture, this._x, this._y);
+ this._texture.drawTextureAt(texture, this._x, this._y);
this._dirty = true;
let letter = new FontLetterDefinition();
- letter.u = this._x + bleed/2;
- letter.v = this._y + bleed/2;
- letter.texture = this._fontDefDictionary._texture;
+ letter.u = this._x + bleed / 2;
+ letter.v = this._y + bleed / 2;
+ letter.texture = this._texture;
+ letter.atlas = this;
+ letter.ref = 0;
letter.valid = true;
letter.w = letterTexture._width - bleed;
letter.h = letterTexture._height - bleed;
+ letter._inCleans = false;
+ letter._hash = letterTexture._hash;
+ letter._width = width;
+ letter._height = height;
letter.xAdvance = letter.w;
letter.offsetY = letterTexture._offsetY;
this._x += width + space;
- this._fontDefDictionary.addLetterDefinitions(letterTexture._hash, letter);
+ this._atlases._fontDefDictionary.addLetterDefinitions(letterTexture._hash, letter);
return letter
},
+ pushFreeLetter(letter) {
+ const i = this.frees.push(letter) - 1;
+ },
+
+ removeFreeLetter(index) {
+ const temp = this.frees[index];
+ const temp2 = this.frees[this.frees.length - 1];
+ // temp2.cacheIndex = index;
+ // temp.cacheIndex = -1;
+ this.frees[index] = temp2;
+ this.frees.pop();
+ },
+
update () {
if (!this._dirty) return;
- this._fontDefDictionary._texture.update();
+ this._texture.update();
this._dirty = false;
},
@@ -192,47 +282,148 @@ cc.js.mixin(LetterAtlas.prototype, {
this._y = space;
this._nexty = space;
- let chars = this._fontDefDictionary._letterDefinitions;
- for (let i = 0, l = chars.length; i < l; i++) {
- let char = chars[i];
- if (!char.isValid) {
- continue;
+ const defs = this._atlases._fontDefDictionary._letterDefinitions;
+ for (const key in defs) {
+ const def = defs[key];
+ if (def.atlas === this) {
+ delete defs[key];
}
- char.destroy();
}
- this._fontDefDictionary.clear();
+ this.frees.length = 0;
+ this.waitCleans.length = 0;
},
destroy () {
this.reset();
- this._fontDefDictionary._texture.destroy();
- this._fontDefDictionary._texture = null;
+ const handler = this._atlases.material.getMultiHandler();
+ handler.removeTexture(this._texture);
+ this._texture.destroy();
+ this._texture = null;
},
- beforeSceneLoad () {
- this.clearAllCache();
- },
+});
- clearAllCache () {
- this.destroy();
+class LetterAtlases {
+
+ /**
+ * 图集数组
+ */
+ atlases = [];
+
+ /**
+ * Char 多纹理材质
+ */
+ material = null;
+
+ /**
+ * Fake MaterialVariant
+ */
+ fakeMaterial = { material: null };
+
+ /**
+ * 抽象图集
+ */
+ _fontDefDictionary = new FontAtlas(null);
- let texture = new RenderTexture();
- texture.initWithSize(this._width, this._height);
- texture.update();
-
- this._fontDefDictionary._texture = texture;
- },
- getLetter (key) {
+ constructor() {
+ const handler = new cc.sp.MultiHandler();
+ this.material = handler.material;
+ this.fakeMaterial.material = this.material;
+
+ cc.director.on(cc.Director.EVENT_BEFORE_SCENE_LAUNCH, this.beforeSceneLoad, this);
+ }
+
+
+ insertLetterTexture(letterTexture) {
+ for (const atlas of this.atlases) {
+ const letter = atlas.insertLetterTexture(letterTexture);
+ if (letter) {
+ return letter;
+ }
+ }
+
+ if (this.atlases.length >= 8) {
+ return null;
+ } else {
+ const atlas = new LetterAtlas(this, _atlasWidth, _atlasHeight);
+ const len = this.atlases.push(atlas);
+ atlas._id = len - 1;
+ const handler = this.material.getMultiHandler();
+ handler.setTexture(atlas._id, atlas._texture);
+ if (!CC_EDITOR && cc.sp.charAtlasAutoBatchCount >= len) {
+ cc.sp.multiBatcher.requsetMaterial(atlas._texture);
+ }
+ return atlas.insertLetterTexture(letterTexture);
+ }
+ }
+
+
+ deleteLetter(letter) {
+ letter.ref--;
+ if (letter.ref === 0 && !letter._inCleans) {
+ letter._inCleans = true;
+ letter.atlas.waitCleans.push(letter);
+ }
+ }
+
+
+ update() {
+ for (const atlas of this.atlases) {
+ atlas.update();
+ }
+ }
+
+
+ reset() {
+ this._fontDefDictionary.clear();
+
+ for (const atlas of this.atlases) {
+ atlas.reset();
+ }
+ }
+
+
+ destroy() {
+ this._fontDefDictionary.clear();
+
+ for (const atlas of this.atlases) {
+ atlas.destroy();
+ }
+
+ this.atlases.length = 0;
+ }
+
+
+ beforeSceneLoad() {
+ if (cc.sp.charAtlasAutoResetBeforeSceneLoad) {
+ this.clearAllCache();
+ }
+ }
+
+
+ clearAllCache() {
+ this.reset();
+ }
+
+
+ getTexture() {
+ if (!_emptyTexture) {
+ _emptyTexture = new RenderTexture();
+ _emptyTexture.initWithSize(_atlasWidth, _atlasHeight);
+ _emptyTexture.update();
+ }
+ return _emptyTexture;
+ }
+
+
+ getLetter(key) {
return this._fontDefDictionary._letterDefinitions[key];
- },
+ }
- getTexture () {
- return this._fontDefDictionary.getTexture();
- },
- getLetterDefinitionForChar: function(char, labelInfo) {
+ getLetterDefinitionForChar(char, labelInfo) {
let hash = char.charCodeAt(0) + labelInfo.hash;
let letter = this._fontDefDictionary._letterDefinitions[hash];
if (!letter) {
@@ -242,12 +433,50 @@ cc.js.mixin(LetterAtlas.prototype, {
temp.destroy();
}
+ if (letter && _firstTraverse) {
+ letter.ref++;
+ _assembler._letterRefs.push(letter);
+ this.checkMaterialAndUpdateTexId(letter);
+ }
+
return letter;
}
-});
+
+
+ checkMaterialAndUpdateTexId(letter) {
+ const atlas = letter.atlas;
+ const comp = _assembler._renderComp;
+
+ // 检查是否需要自动切换材质
+ if (_needCheckMaterial) {
+ _needCheckMaterial = false;
+ if (_usedMaterial.material !== _shareAtlas.material) {
+ _assembler.checkAndSwitchMaterial(comp, atlas._texture, _usedMaterial);
+ _usedMaterial = comp._materials[0];
+ }
+ }
+
+ // 检查是否需要更新 atlas tmpId使用内置材质则不检查
+ if (_usedMaterial.material !== _shareAtlas.material && atlas._tmpId === -1) {
+ const handler = _usedMaterial.material.getMultiHandler();
+ if (handler) {
+ const index = handler.getIndex(atlas._texture.getImpl());
+ if (index !== -1) {
+ atlas._tmpId = index;
+ return;
+ }
+ }
+
+ // 如果无法在材质中找到 texture则切换至内置材质
+ comp.setMaterial(0, _shareAtlas.material);
+ _usedMaterial = _shareAtlas.fakeMaterial;
+ }
+ }
+
+}
function computeHash (labelInfo) {
- let hashData = '';
+ let hashData = '|';
let color = labelInfo.color.toHEX();
let out = '';
if (labelInfo.isOutlined && labelInfo.margin > 0) {
@@ -262,11 +491,31 @@ let _shareAtlas = null;
let _atlasWidth = 2048;
let _atlasHeight = 2048;
let _isBold = false;
+let _usedMaterial = null;
+let _needCheckMaterial = false;
+let _firstTraverse = false;
+let _assembler = null;
+let _emptyTexture = null;
export default class LetterFontAssembler extends WebglBmfontAssembler {
+ _letterRefs = [];
+
+ initData() {
+ let data = this._renderData;
+ data.createFlexData(0, this.verticesCount, this.indicesCount, this.getVfmt());
+ }
+
+ getVfmt() {
+ return vfmtPosUvColorTexId;
+ }
+
+ getBuffer() {
+ return cc.renderer._handle.getBuffer("mesh", this.getVfmt());
+ }
+
_getAssemblerData () {
if (!_shareAtlas) {
- _shareAtlas = new LetterAtlas(_atlasWidth, _atlasHeight);
+ _shareAtlas = new LetterAtlases();
cc.Label._shareAtlas = _shareAtlas;
}
@@ -310,4 +559,64 @@ export default class LetterFontAssembler extends WebglBmfontAssembler {
_determineRect (tempRect) {
return false;
}
-}
\ No newline at end of file
+
+ _updateRenderData(comp) {
+ // 还原 tex id 与当前使用材质
+ _assembler = this;
+ _usedMaterial = _assembler._renderComp._materials[0];
+ _needCheckMaterial = true;
+ _firstTraverse = true;
+ for (const atlas of _shareAtlas.atlases) {
+ atlas._tmpId = -1;
+ }
+
+ // 还原 letterRef
+ this._recycleLetterRef();
+
+ super._updateRenderData(comp);
+
+ _usedMaterial = null;
+ _assembler = null;
+ }
+
+ _finishMultilineTextWrap() {
+ _firstTraverse = false;
+ }
+
+ _recycleLetterRef() {
+ for (const letter of this._letterRefs) {
+ _shareAtlas.deleteLetter(letter);
+ }
+ this._letterRefs.length = 0;
+ }
+
+ _resetAssemblerData(assemblerData) {
+ if (this._letterRefs.length !== 0) {
+ this._recycleLetterRef();
+ }
+ }
+
+ appendVerts(comp, offset, l, r, b, t, letter) {
+ super.appendVerts(comp, offset, l, r, b, t, letter);
+
+ // update texId
+ const renderData = this._renderData;
+ const verts = renderData.vDatas[0];
+ const floatsPerVert = this.floatsPerVert;
+ let texIdOffset = offset + this.texIdOffset;
+ const id = _usedMaterial.material !== _shareAtlas.material ? letter.atlas._tmpId : letter.atlas._id;
+
+ verts[texIdOffset] = id;
+ texIdOffset += floatsPerVert;
+ verts[texIdOffset] = id;
+ texIdOffset += floatsPerVert;
+ verts[texIdOffset] = id;
+ texIdOffset += floatsPerVert;
+ verts[texIdOffset] = id;
+ }
+
+}
+
+LetterFontAssembler.prototype.floatsPerVert = 6;
+LetterFontAssembler.prototype.texIdOffset = 5;
+LetterFontAssembler.prototype.isMulti = true;
diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/label/2d/bmfont.js b/engine/cocos2d/core/renderer/webgl/assemblers/label/2d/bmfont.js
index be7d330..db1904a 100644
--- a/engine/cocos2d/core/renderer/webgl/assemblers/label/2d/bmfont.js
+++ b/engine/cocos2d/core/renderer/webgl/assemblers/label/2d/bmfont.js
@@ -65,7 +65,7 @@ export default class WebglBmfontAssembler extends BmfontAssembler {
return comp.node._color._val;
}
- appendQuad (comp, texture, rect, rotated, x, y, scale) {
+ appendQuad(comp, texture, rect, rotated, x, y, scale, letter) {
let renderData = this._renderData;
let verts = renderData.vDatas[0],
uintVerts = renderData.uintVDatas[0];
@@ -131,7 +131,7 @@ export default class WebglBmfontAssembler extends BmfontAssembler {
b = y - rectHeight * scale;
t = y;
- this.appendVerts(comp, _dataOffset, l, r, b, t);
+ this.appendVerts(comp, _dataOffset, l, r, b, t, letter);
// colors
let colorOffset = _dataOffset + this.colorOffset;
@@ -143,7 +143,7 @@ export default class WebglBmfontAssembler extends BmfontAssembler {
_dataOffset += this.floatsPerVert * 4;
}
- appendVerts (comp, offset, l, r, b, t) {
+ appendVerts(comp, offset, l, r, b, t, letter) {
let local = this._local;
let floatsPerVert = this.floatsPerVert;
--
2.32.0 (Apple Git-132)