cocos-enhance-kit/patches/v1.0.0/0009-Char.patch

620 lines
20 KiB
Diff
Raw Normal View History

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/15] =?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)