From 48dfcac3417cd4d1a08e9f3d75f997e05092544b Mon Sep 17 00:00:00 2001 From: SmallMain Date: Wed, 6 Jul 2022 00:03:30 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8D=E5=86=8D=E5=B0=86=20patches=20?= =?UTF-8?q?=E5=AD=98=E5=88=B0=E4=BB=93=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README-DEV.md | 3 +- patches/v1.0.0/0001-.patch | 24 - patches/v1.0.0/0002-SP.patch | 30 - patches/v1.0.0/0003-Effect-hash.patch | 111 - patches/v1.0.0/0004-sp.patch | 568 ----- ...c.RichText-cc.Sprite-cc.MotionStreak.patch | 2078 ----------------- patches/v1.0.0/0006-.patch | 1236 ---------- patches/v1.0.0/0007-RichText.patch | 103 - patches/v1.0.0/0008-DPI.patch | 275 --- patches/v1.0.0/0009-Char.patch | 619 ----- patches/v1.0.0/0010-Spine-region-API.patch | 799 ------- patches/v1.0.0/0011-.patch | 146 -- patches/v1.0.0/0012-cc.MotionStreak.patch | 47 - patches/v1.0.0/0013-Spine.patch | 134 -- patches/v1.0.0/0014-Char.patch | 33 - patches/v1.0.0/0015-Bitmap-uuid.patch | 55 - patches/v1.0.0/0016-Spine-assembler.patch | 39 - 17 files changed, 1 insertion(+), 6299 deletions(-) delete mode 100644 patches/v1.0.0/0001-.patch delete mode 100644 patches/v1.0.0/0002-SP.patch delete mode 100644 patches/v1.0.0/0003-Effect-hash.patch delete mode 100644 patches/v1.0.0/0004-sp.patch delete mode 100644 patches/v1.0.0/0005-cc.Label-cc.RichText-cc.Sprite-cc.MotionStreak.patch delete mode 100644 patches/v1.0.0/0006-.patch delete mode 100644 patches/v1.0.0/0007-RichText.patch delete mode 100644 patches/v1.0.0/0008-DPI.patch delete mode 100644 patches/v1.0.0/0009-Char.patch delete mode 100644 patches/v1.0.0/0010-Spine-region-API.patch delete mode 100644 patches/v1.0.0/0011-.patch delete mode 100644 patches/v1.0.0/0012-cc.MotionStreak.patch delete mode 100644 patches/v1.0.0/0013-Spine.patch delete mode 100644 patches/v1.0.0/0014-Char.patch delete mode 100644 patches/v1.0.0/0015-Bitmap-uuid.patch delete mode 100644 patches/v1.0.0/0016-Spine-assembler.patch diff --git a/README-DEV.md b/README-DEV.md index d14d3870..4ff56cfa 100644 --- a/README-DEV.md +++ b/README-DEV.md @@ -18,7 +18,6 @@ - `extension` 引擎扩展 - `docs` 存放着文档网站源码,使用 Docusaurus 开发。 - `demo` 存放着 Cocos Creator 演示项目源码。 -- `patches` 存放着所有引擎改动的 Git Patch。 ## 发布新版本 @@ -37,7 +36,7 @@ ### 准备压缩包 -1.将对 engine 的改动整合到 Git Patch,然后将 Patch 按相应的引擎目录放置在仓库的 `patches` 目录中,并放在压缩包根目录内。 +1.将对 engine 的改动整合到 Git Patch,然后将 Patch 按相应的引擎目录放置在 `patches` 目录并放在压缩包根目录内。 2.编译 JavaScript 引擎和原生模拟器,再将三个引擎目录放到压缩包根目录内,包括类型提示文件。 3.将 `service-pack-support` 目录放在压缩包根目录内。 4.更新文档的更新日志。 diff --git a/patches/v1.0.0/0001-.patch b/patches/v1.0.0/0001-.patch deleted file mode 100644 index 8ad72168..00000000 --- a/patches/v1.0.0/0001-.patch +++ /dev/null @@ -1,24 +0,0 @@ -From e18df36c0f2a9f01ea59ad82e927881a0ee6727f Mon Sep 17 00:00:00 2001 -From: SmallMain -Date: Tue, 21 Jun 2022 10:09:44 +0800 -Subject: [PATCH 01/16] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=89=88=E6=9C=AC?= - =?UTF-8?q?=E5=8F=B7=E8=AF=86=E5=88=AB=E6=96=87=E4=BB=B6?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - ---- - engine/VERSION | 1 + - 1 file changed, 1 insertion(+) - create mode 100644 engine/VERSION - -diff --git a/engine/VERSION b/engine/VERSION -new file mode 100644 -index 0000000..3eefcb9 ---- /dev/null -+++ b/engine/VERSION -@@ -0,0 +1 @@ -+1.0.0 --- -2.32.0 (Apple Git-132) - diff --git a/patches/v1.0.0/0002-SP.patch b/patches/v1.0.0/0002-SP.patch deleted file mode 100644 index 8371b0fb..00000000 --- a/patches/v1.0.0/0002-SP.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 18ced62a549cad18aba00938d10a86d7ec06fc0d Mon Sep 17 00:00:00 2001 -From: SmallMain -Date: Tue, 21 Jun 2022 10:16:01 +0800 -Subject: [PATCH 02/16] =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8F=B7=E8=BE=93?= - =?UTF-8?q?=E5=87=BA=E4=B8=AD=E5=A2=9E=E5=8A=A0=20=E2=80=9CSP=E2=80=9D=20?= - =?UTF-8?q?=E6=A0=87=E8=AF=86?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - ---- - engine/cocos2d/core/CCGame.js | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/engine/cocos2d/core/CCGame.js b/engine/cocos2d/core/CCGame.js -index c7ca11e..dec82da 100644 ---- a/engine/cocos2d/core/CCGame.js -+++ b/engine/cocos2d/core/CCGame.js -@@ -390,7 +390,7 @@ var game = { - this._setAnimFrame(); - cc.assetManager.builtins.init(() => { - // Log engine version -- console.log('Cocos Creator v' + cc.ENGINE_VERSION); -+ console.log('Cocos Creator SP v' + cc.ENGINE_VERSION); - this._prepared = true; - this._runMainLoop(); - --- -2.32.0 (Apple Git-132) - diff --git a/patches/v1.0.0/0003-Effect-hash.patch b/patches/v1.0.0/0003-Effect-hash.patch deleted file mode 100644 index 65cd4ea9..00000000 --- a/patches/v1.0.0/0003-Effect-hash.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 5adb675810523f2c136f1e157bbdaf28d8bd3dfc Mon Sep 17 00:00:00 2001 -From: SmallMain -Date: Tue, 21 Jun 2022 10:17:09 +0800 -Subject: [PATCH 03/16] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20Effect=20=E4=BF=AE?= - =?UTF-8?q?=E6=94=B9=E5=90=8E=EF=BC=8C=E5=85=B6=E5=8F=98=E4=BD=93=20hash?= - =?UTF-8?q?=20=E5=80=BC=E4=B8=8D=E4=BC=9A=E5=88=B7=E6=96=B0=E7=9A=84?= - =?UTF-8?q?=E9=97=AE=E9=A2=98?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - ---- - engine/cocos2d/core/assets/material/effect-base.ts | 7 +++++++ - engine/cocos2d/core/assets/material/effect-variant.ts | 8 +++++--- - 2 files changed, 12 insertions(+), 3 deletions(-) - -diff --git a/engine/cocos2d/core/assets/material/effect-base.ts b/engine/cocos2d/core/assets/material/effect-base.ts -index 578f27d..69c98fa 100644 ---- a/engine/cocos2d/core/assets/material/effect-base.ts -+++ b/engine/cocos2d/core/assets/material/effect-base.ts -@@ -4,6 +4,7 @@ const gfx = cc.gfx; - - export default class EffectBase { - _dirty = true; -+ _dirtyCode = 0; - - _name = ''; - get name () { -@@ -54,6 +55,7 @@ export default class EffectBase { - } - - this._dirty = true; -+ this._dirtyCode++; - return Pass.prototype.setProperty.call(pass, name, value, directly); - } - -@@ -132,6 +134,7 @@ export default class EffectBase { - passes[i].setCullMode(cullMode); - } - this._dirty = true; -+ this._dirtyCode++; - } - - setDepth (depthTest, depthWrite, depthFunc, passIdx) { -@@ -144,6 +147,7 @@ export default class EffectBase { - passes[i].setDepth(depthTest, depthWrite, depthFunc); - } - this._dirty = true; -+ this._dirtyCode++; - } - - setBlend (enabled, blendEq, blendSrc, blendDst, blendAlphaEq, blendSrcAlpha, blendDstAlpha, blendColor, passIdx) { -@@ -162,6 +166,7 @@ export default class EffectBase { - ); - } - this._dirty = true; -+ this._dirtyCode++; - } - - setStencilEnabled (stencilTest = gfx.STENCIL_INHERIT, passIdx) { -@@ -174,6 +179,7 @@ export default class EffectBase { - passes[i].setStencilEnabled(stencilTest); - } - this._dirty = true; -+ this._dirtyCode++; - } - - setStencil (enabled, stencilFunc, stencilRef, stencilMask, stencilFailOp, stencilZFailOp, stencilZPassOp, stencilWriteMask, passIdx) { -@@ -188,6 +194,7 @@ export default class EffectBase { - pass.setStencilBack(enabled, stencilFunc, stencilRef, stencilMask, stencilFailOp, stencilZFailOp, stencilZPassOp, stencilWriteMask); - } - this._dirty = true; -+ this._dirtyCode++; - } - } - -diff --git a/engine/cocos2d/core/assets/material/effect-variant.ts b/engine/cocos2d/core/assets/material/effect-variant.ts -index 5623ed1..1b4b134 100644 ---- a/engine/cocos2d/core/assets/material/effect-variant.ts -+++ b/engine/cocos2d/core/assets/material/effect-variant.ts -@@ -11,6 +11,7 @@ export default class EffectVariant extends EffectBase { - _passes: Pass[] = []; - _stagePasses = {}; - _hash = 0; -+ _effectDirtyCode = 0; - - get effect () { - return this._effect; -@@ -66,15 +67,16 @@ export default class EffectVariant extends EffectBase { - - } - -- getHash () { -- if (!this._dirty) return this._hash; -+ getHash() { -+ let effect = this._effect; -+ if (!this._dirty && (!effect || this._effectDirtyCode === effect._dirtyCode)) return this._hash; - this._dirty = false; - - let hash = ''; - hash += utils.serializePasses(this._passes); - -- let effect = this._effect; - if (effect) { -+ this._effectDirtyCode = effect._dirtyCode; - hash += utils.serializePasses(effect.passes); - } - --- -2.32.0 (Apple Git-132) - diff --git a/patches/v1.0.0/0004-sp.patch b/patches/v1.0.0/0004-sp.patch deleted file mode 100644 index 92aef363..00000000 --- a/patches/v1.0.0/0004-sp.patch +++ /dev/null @@ -1,568 +0,0 @@ -From 6816546edb39321714e08ad5332995dfabdc6f03 Mon Sep 17 00:00:00 2001 -From: SmallMain -Date: Tue, 21 Jun 2022 10:31:13 +0800 -Subject: [PATCH 04/16] =?UTF-8?q?sp=E3=80=81=E5=A4=9A=E7=BA=B9=E7=90=86?= - =?UTF-8?q?=E6=B8=B2=E6=9F=93=20-=20=E5=9F=BA=E7=A1=80=E6=A0=B8=E5=BF=83?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - ---- - engine/cocos2d/core/asset-manager/builtins.js | 44 +++++- - engine/cocos2d/core/assets/CCTexture2D.js | 43 +++++- - .../core/assets/material/CCMaterial.js | 36 +++++ - engine/cocos2d/core/index.js | 2 + - engine/cocos2d/core/sp/index.js | 3 + - engine/cocos2d/core/sp/multi-batcher.ts | 74 +++++++++ - engine/cocos2d/core/sp/multi-handler.ts | 146 ++++++++++++++++++ - engine/cocos2d/core/sp/sp.js | 86 +++++++++++ - 8 files changed, 432 insertions(+), 2 deletions(-) - create mode 100644 engine/cocos2d/core/sp/index.js - create mode 100644 engine/cocos2d/core/sp/multi-batcher.ts - create mode 100644 engine/cocos2d/core/sp/multi-handler.ts - create mode 100644 engine/cocos2d/core/sp/sp.js - -diff --git a/engine/cocos2d/core/asset-manager/builtins.js b/engine/cocos2d/core/asset-manager/builtins.js -index ae8cca7..f794369 100644 ---- a/engine/cocos2d/core/asset-manager/builtins.js -+++ b/engine/cocos2d/core/asset-manager/builtins.js -@@ -80,10 +80,52 @@ var builtins = { - } - - this._loadBuiltins('effect', () => { -- this._loadBuiltins('material', cb); -+ this._loadBuiltins('material', () => { -+ this._loadBuiltinsSP(cb); -+ }); -+ }); -+ }, -+ -+ _loadBuiltinsSP(cb) { -+ cc.sp.MAX_MULTITEXTURE_NUM = 8; -+ // cc.renderer.device.caps.maxTextureUnits -+ -+ this._loadMultiEffect('multi-2d-sprite', (effect) => { -+ cc.sp.multi2dSpriteEffectAsset = effect; -+ effect.addRef(); -+ cc.sp.inited = true; -+ cc.sp.multiBatcher.init(); -+ -+ cb(); - }); - }, - -+ _loadMultiEffect(name, cb) { -+ if (CC_EDITOR) { -+ cc.assetManager.loadAny(Editor.assetdb.remote.urlToUuid('db://service-pack-resources/sp/effects/' + name + '.effect'), function (err, effect) { -+ if (err) { -+ return Editor.error(err); -+ } else { -+ cb(effect); -+ } -+ }); -+ } else { -+ cc.assetManager.loadBundle('sp', (err, bundle) => { -+ if (err) { -+ cc.error(err); -+ } else { -+ bundle.load('effects/' + name, cc.EffectAsset, (err, effect) => { -+ if (err) { -+ cc.error(err); -+ } else { -+ cb(effect); -+ } -+ }); -+ } -+ }); -+ } -+ }, -+ - /** - * !#en - * Get the built-in asset using specific type and name. -diff --git a/engine/cocos2d/core/assets/CCTexture2D.js b/engine/cocos2d/core/assets/CCTexture2D.js -index 3863538..e823c45 100644 ---- a/engine/cocos2d/core/assets/CCTexture2D.js -+++ b/engine/cocos2d/core/assets/CCTexture2D.js -@@ -470,6 +470,9 @@ var Texture2D = cc.Class({ - if (CC_EDITOR) { - this._exportedExts = null; - } -+ -+ // multi batcher -+ this._multiMaterial = null; - }, - - /** -@@ -688,6 +691,8 @@ var Texture2D = cc.Class({ - } - this._packable && cc.dynamicAtlasManager && cc.dynamicAtlasManager.deleteAtlasTexture(this); - -+ this.unlinkMaterial(); -+ - this._image = null; - this._texture && this._texture.destroy(); - this._super(); -@@ -1050,7 +1055,43 @@ var Texture2D = cc.Class({ - else { - cb(); - } -- } -+ }, -+ -+ linkMaterial(material, index) { -+ const handler = material.getMultiHandler(); -+ if (handler) { -+ if (index == null) { -+ if (handler.autoSetTexture(this) === -1) { -+ return false; -+ } -+ } else { -+ handler.setTexture(index, this); -+ } -+ this.unlinkMaterial(); -+ this._multiMaterial = material; -+ return true; -+ } else { -+ return false; -+ } -+ }, -+ -+ unlinkMaterial() { -+ if (this._multiMaterial) { -+ const handler = this._multiMaterial.getMultiHandler(); -+ const _texture = this.getImpl(); -+ handler.removeTexture(_texture); -+ this._multiMaterial = null; -+ } -+ }, -+ -+ getLinkedMaterial() { -+ return this._multiMaterial; -+ }, -+ -+ hasLinkedMaterial() { -+ return !!this._multiMaterial; -+ }, -+ - }); - - /** -diff --git a/engine/cocos2d/core/assets/material/CCMaterial.js b/engine/cocos2d/core/assets/material/CCMaterial.js -index e0249b3..2251347 100644 ---- a/engine/cocos2d/core/assets/material/CCMaterial.js -+++ b/engine/cocos2d/core/assets/material/CCMaterial.js -@@ -72,6 +72,7 @@ let Material = cc.Class({ - this._manualHash = false; - this._dirty = true; - this._effect = null; -+ this._multiHandler = null; - }, - - properties: { -@@ -124,6 +125,8 @@ let Material = cc.Class({ - } - - this._effect = this._effectAsset.getInstantiatedEffect(); -+ -+ this.updateMultiSupport(); - } - }, - -@@ -140,6 +143,7 @@ let Material = cc.Class({ - set (v) { - this._techniqueIndex = v; - this._effect.switchTechnique(v); -+ this.updateMultiSupport(); - } - } - }, -@@ -401,7 +405,39 @@ let Material = cc.Class({ - } - } - -+ this.updateMultiSupport(); -+ if (this._multiHandler) this._multiHandler.syncTextures(); -+ }, -+ -+ updateMultiSupport() { -+ const passes = this._effect.technique.passes; -+ if (passes.length > 0 && passes[0].getDefine("USE_MULTI_TEXTURE")) { -+ this.setMultiSupport(true); -+ } else { -+ this.setMultiSupport(false); -+ } - }, -+ -+ isMultiSupport() { -+ return !!this._multiHandler; -+ }, -+ -+ setMultiSupport(bool) { -+ if (bool) { -+ if (this._multiHandler) { -+ this._multiHandler.syncTextures(); -+ } else { -+ this._multiHandler = new cc.sp.MultiHandler(this); -+ } -+ } else if (!bool) { -+ this._multiHandler = null; -+ } -+ }, -+ -+ getMultiHandler() { -+ return this._multiHandler; -+ }, -+ - }); - - export default Material; -diff --git a/engine/cocos2d/core/index.js b/engine/cocos2d/core/index.js -index d7e79d1..a0eda10 100644 ---- a/engine/cocos2d/core/index.js -+++ b/engine/cocos2d/core/index.js -@@ -40,6 +40,8 @@ if (!CC_EDITOR || !Editor.isMainProcess) { - require('./physics'); - require('./camera/CCCamera'); - require('./geom-utils'); -+ -+ require('./sp'); - } - - require('./mesh'); -diff --git a/engine/cocos2d/core/sp/index.js b/engine/cocos2d/core/sp/index.js -new file mode 100644 -index 0000000..fa17f6f ---- /dev/null -+++ b/engine/cocos2d/core/sp/index.js -@@ -0,0 +1,3 @@ -+require('./sp'); -+require('./multi-handler'); -+require('./multi-batcher'); -diff --git a/engine/cocos2d/core/sp/multi-batcher.ts b/engine/cocos2d/core/sp/multi-batcher.ts -new file mode 100644 -index 0000000..dd18ab2 ---- /dev/null -+++ b/engine/cocos2d/core/sp/multi-batcher.ts -@@ -0,0 +1,74 @@ -+import { MultiHandler } from "./multi-handler"; -+ -+ -+/** -+ * 多纹理合批器 -+ */ -+export class MultiBatcher { -+ -+ /** -+ * 多纹理材质管理器数组 -+ */ -+ handlers: MultiHandler[] = []; -+ -+ /** -+ * 有空槽的材质 -+ */ -+ nextHandler!: MultiHandler; -+ -+ -+ /** -+ * 初始化 -+ */ -+ init() { -+ const handler = new MultiHandler(); -+ this.handlers.push(handler); -+ this.nextHandler = handler; -+ } -+ -+ -+ /** -+ * 传入 cc.Texture2D,会关联并返回一个多纹理材质,如果已经有关联的材质则会返回已关联的材质 -+ */ -+ requsetMaterial(texture: any) { -+ if (!texture._multiMaterial) { -+ let handler = this.nextHandler; -+ let index = handler.getEmptyIndex(); -+ if (index === -1) { -+ // 没有空位,尝试在已有 handlers 里查找 -+ for (const _handler of this.handlers) { -+ index = _handler.getEmptyIndex(); -+ if (index !== -1) { -+ handler = _handler; -+ this.nextHandler = handler; -+ break; -+ } -+ } -+ -+ // 已有的没有空位,创建新材质 -+ if (index === -1) { -+ handler = new MultiHandler(); -+ this.handlers.push(handler); -+ this.nextHandler = handler; -+ index = 0; -+ } -+ } -+ -+ texture.linkMaterial(handler.material, index); -+ } -+ return texture._multiMaterial; -+ } -+ -+ -+ /** -+ * 重置多纹理材质数组,再次使用请先初始化 -+ */ -+ reset() { -+ this.handlers.length = 0; -+ } -+ -+} -+ -+ -+cc.sp.multiBatcher = new MultiBatcher(); -+cc.sp.MultiBatcher = MultiBatcher; -diff --git a/engine/cocos2d/core/sp/multi-handler.ts b/engine/cocos2d/core/sp/multi-handler.ts -new file mode 100644 -index 0000000..664876e ---- /dev/null -+++ b/engine/cocos2d/core/sp/multi-handler.ts -@@ -0,0 +1,146 @@ -+/** -+ * 多纹理 Material 管理类 -+ */ -+export class MultiHandler { -+ -+ /** -+ * 材质 -+ */ -+ material: any; -+ -+ /** -+ * Texture 数组 -+ * -+ * 注意:不是 cc.Texture2D -+ */ -+ protected textures: any[] = []; -+ -+ /** -+ * 有空槽(缓存值,并不是完全正确,只是为了降低当材质没有空槽时避免数组遍历的性能消耗) -+ */ -+ protected hasEmptySlot: boolean = false; -+ -+ -+ constructor(material?) { -+ if (material) { -+ this.material = material; -+ } else { -+ this.material = (cc.Material as any).create(cc.sp.multi2dSpriteEffectAsset); -+ this.material.name = "multi-2d-sprite"; -+ this.material.define('USE_TEXTURE', true); -+ this.material.define('USE_MULTI_TEXTURE', true); -+ } -+ this.material._multiHandler = this; -+ this.syncTextures(); -+ } -+ -+ -+ /** -+ * 同步 Material 的纹理插槽数据 -+ * -+ * 当自行设置插槽可调用此函数同步数组 -+ */ -+ syncTextures() { -+ const effect = this.material['effect']; -+ const properties = effect.passes[0]._properties; -+ -+ this.textures[0] = properties.texture.value; -+ this.textures[1] = properties.texture2.value; -+ this.textures[2] = properties.texture3.value; -+ this.textures[3] = properties.texture4.value; -+ this.textures[4] = properties.texture5.value; -+ this.textures[5] = properties.texture6.value; -+ this.textures[6] = properties.texture7.value; -+ this.textures[7] = properties.texture8.value; -+ -+ // refresh has empty slot state -+ this.hasEmptySlot = true; -+ this.getEmptyIndex(); -+ } -+ -+ -+ /** -+ * 设置纹理插槽(提供 cc.Texture2D) -+ */ -+ setTexture(index: number, texture: any) { -+ this.textures[index] = texture ? texture.getImpl() : null; -+ this.material.setProperty(cc.sp.propertyIndex2Name(index), texture); -+ if (texture == null) this.hasEmptySlot = true; -+ } -+ -+ -+ /** -+ * 移除指定纹理 -+ * -+ * 注意:不是 cc.Texture2D -+ */ -+ removeTexture(texture: any) { -+ const index = this.getIndex(texture); -+ if (index !== -1) { -+ this.setTexture(index, null); -+ } -+ } -+ -+ -+ /** -+ * 纹理是否在插槽中 -+ * -+ * 注意:不是 cc.Texture2D -+ */ -+ hasTexture(texture: any) { -+ return this.textures.indexOf(texture) !== -1; -+ } -+ -+ -+ /** -+ * 获取纹理在插槽中的 Index,没有返回 -1 -+ * -+ * 注意:不是 cc.Texture2D -+ */ -+ getIndex(texture: any) { -+ return this.textures.indexOf(texture); -+ } -+ -+ -+ /** -+ * 获取指定 index 中的纹理 -+ * -+ * 注意:不是 cc.Texture2D -+ */ -+ getTexture(index: number) { -+ return this.textures[index]; -+ } -+ -+ -+ /** -+ * 获取空插槽 Index,没有返回 -1 -+ */ -+ getEmptyIndex() { -+ if (!this.hasEmptySlot) return -1; -+ const index = this.textures.indexOf(null); -+ if (index !== -1) { -+ return index; -+ } else { -+ this.hasEmptySlot = false; -+ return -1; -+ } -+ } -+ -+ -+ /** -+ * 自动设置纹理到空插槽,返回插槽下标,失败返回 -1(提供 cc.Texture2D) -+ */ -+ autoSetTexture(texture: any) { -+ const index = this.getEmptyIndex(); -+ if (index === -1) { -+ return -1; -+ } -+ -+ this.setTexture(index, texture); -+ return index; -+ } -+ -+} -+ -+ -+cc.sp.MultiHandler = MultiHandler; -diff --git a/engine/cocos2d/core/sp/sp.js b/engine/cocos2d/core/sp/sp.js -new file mode 100644 -index 0000000..956a003 ---- /dev/null -+++ b/engine/cocos2d/core/sp/sp.js -@@ -0,0 +1,86 @@ -+cc.sp = { -+ -+ /** -+ * 是否初始化完成 -+ */ -+ inited: false, -+ -+ /** -+ * 版本号 -+ */ -+ version: "1.0.0", -+ -+ /** -+ * 最大纹理插槽数量 -+ * -+ * 固定为 8 -+ */ -+ MAX_MULTITEXTURE_NUM: -1, -+ -+ /** -+ * 渲染组件是否默认自动切换至贴图关联的材质 -+ */ -+ autoSwitchMaterial: true, -+ -+ /** -+ * 渲染组件是否默认参与动态合图 -+ */ -+ allowDynamicAtlas: true, -+ -+ /** -+ * Label 组件是否默认启用渲染时进行缩放以适配高 DPI 屏幕 -+ */ -+ enableLabelRetina: true, -+ -+ /** -+ * Label 组件渲染时进行缩放的缩放比例 -+ */ -+ labelRetinaScale: 1, -+ -+ /** -+ * Char 图集会进行自动多纹理合批的数量 -+ */ -+ charAtlasAutoBatchCount: 1, -+ -+ /** -+ * Char 图集是否在场景切换时清空 -+ */ -+ charAtlasAutoResetBeforeSceneLoad: true, -+ -+ /** -+ * 内置的多纹理合批 Effect Asset -+ */ -+ multi2dSpriteEffectAsset: null, -+ -+ /** -+ * property index to name map -+ */ -+ i2nMap: ['texture'], -+ -+ /** -+ * property name to index map -+ */ -+ n2iMap: { texture: 0 }, -+ -+ /** -+ * property index to name -+ */ -+ propertyIndex2Name(index) { -+ return this.i2nMap[index]; -+ }, -+ -+ /** -+ * property name to index -+ */ -+ propertyName2Index(name) { -+ return this.n2iMap[name]; -+ }, -+ -+}; -+ -+// 初始化 -+for (let i = 1; i < 8; i++) { -+ const name = "texture" + (i + 1); -+ cc.sp.i2nMap[i] = name; -+ cc.sp.n2iMap[name] = i; -+} --- -2.32.0 (Apple Git-132) - diff --git a/patches/v1.0.0/0005-cc.Label-cc.RichText-cc.Sprite-cc.MotionStreak.patch b/patches/v1.0.0/0005-cc.Label-cc.RichText-cc.Sprite-cc.MotionStreak.patch deleted file mode 100644 index cd4f548c..00000000 --- a/patches/v1.0.0/0005-cc.Label-cc.RichText-cc.Sprite-cc.MotionStreak.patch +++ /dev/null @@ -1,2078 +0,0 @@ -From 0f2dafc3798f563b4302333ac90e3e2f1c3f2cc7 Mon Sep 17 00:00:00 2001 -From: SmallMain -Date: Tue, 21 Jun 2022 11:30:54 +0800 -Subject: [PATCH 05/16] =?UTF-8?q?=E5=A4=9A=E7=BA=B9=E7=90=86=E6=B8=B2?= - =?UTF-8?q?=E6=9F=93=20-=20cc.Label=E3=80=81cc.RichText=E3=80=81cc.Sprite?= - =?UTF-8?q?=E3=80=81cc.MotionStreak=20=E7=BB=84=E4=BB=B6=E7=9A=84=E5=8E=9F?= - =?UTF-8?q?=E7=94=9F=E6=94=AF=E6=8C=81?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - ---- - engine/cocos2d/core/components/CCLabel.js | 27 +- - .../cocos2d/core/components/CCMotionStreak.js | 46 +++- - .../core/components/CCRenderComponent.js | 72 +++++- - engine/cocos2d/core/components/CCRichText.js | 32 ++- - engine/cocos2d/core/components/CCSprite.js | 29 ++- - engine/cocos2d/core/platform/CCMacro.js | 4 +- - engine/cocos2d/core/renderer/assembler-2d.js | 25 +- - engine/cocos2d/core/renderer/assembler.js | 53 ++++ - .../core/renderer/utils/label/bmfont.js | 26 +- - .../cocos2d/core/renderer/utils/label/ttf.js | 13 +- - .../core/renderer/webgl/assemblers/index.js | 3 +- - .../webgl/assemblers/label/2d-multi/bmfont.js | 71 ++++++ - .../webgl/assemblers/label/2d-multi/ttf.js | 72 ++++++ - .../renderer/webgl/assemblers/label/index.js | 15 +- - .../webgl/assemblers/motion-streak-multi.js | 233 ++++++++++++++++++ - .../webgl/assemblers/motion-streak.js | 3 - - .../assemblers/sprite/2d-multi/bar-filled.js | 99 ++++++++ - .../webgl/assemblers/sprite/2d-multi/mesh.js | 94 +++++++ - .../sprite/2d-multi/radial-filled.js | 70 ++++++ - .../assemblers/sprite/2d-multi/simple.js | 76 ++++++ - .../assemblers/sprite/2d-multi/sliced.js | 89 +++++++ - .../webgl/assemblers/sprite/2d-multi/tiled.js | 99 ++++++++ - .../webgl/assemblers/sprite/2d/bar-filled.js | 47 ++-- - .../webgl/assemblers/sprite/2d/mesh.js | 48 ++-- - .../assemblers/sprite/2d/radial-filled.js | 11 +- - .../webgl/assemblers/sprite/2d/simple.js | 13 +- - .../webgl/assemblers/sprite/2d/sliced.js | 15 +- - .../webgl/assemblers/sprite/2d/tiled.js | 63 ++--- - .../renderer/webgl/assemblers/sprite/index.js | 28 ++- - .../core/renderer/webgl/vertex-format.js | 14 +- - engine/cocos2d/renderer/gfx/enums.js | 3 +- - engine/modules.json | 3 +- - 32 files changed, 1359 insertions(+), 137 deletions(-) - create mode 100644 engine/cocos2d/core/renderer/webgl/assemblers/label/2d-multi/bmfont.js - create mode 100644 engine/cocos2d/core/renderer/webgl/assemblers/label/2d-multi/ttf.js - create mode 100644 engine/cocos2d/core/renderer/webgl/assemblers/motion-streak-multi.js - create mode 100644 engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/bar-filled.js - create mode 100644 engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/mesh.js - create mode 100644 engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/radial-filled.js - create mode 100644 engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/simple.js - create mode 100644 engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/sliced.js - create mode 100644 engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/tiled.js - -diff --git a/engine/cocos2d/core/components/CCLabel.js b/engine/cocos2d/core/components/CCLabel.js -index 81e3cd4..f2c372f 100644 ---- a/engine/cocos2d/core/components/CCLabel.js -+++ b/engine/cocos2d/core/components/CCLabel.js -@@ -192,7 +192,7 @@ let Label = cc.Class({ - editor: CC_EDITOR && { - menu: 'i18n:MAIN_MENU.component.renderers/Label', - help: 'i18n:COMPONENT.help_url.label', -- inspector: 'packages://inspector/inspectors/comps/label.js', -+ inspector: 'packages://service-pack/inspectors/comps/label.js', - }, - - properties: { -@@ -578,6 +578,11 @@ let Label = cc.Class({ - }, - tooltip: CC_DEV && 'i18n:COMPONENT.label.underline_height', - }, -+ -+ autoSwitchMaterial: { -+ type: RenderComponent.EnableType, -+ default: RenderComponent.EnableType.GLOBAL, -+ }, - }, - - statics: { -@@ -782,7 +787,25 @@ let Label = cc.Class({ - } - - if (!this._frame) return; -- material && material.setProperty('texture', this._frame._texture); -+ -+ if (material) { -+ // 根据材质更新 uniform -+ const isMultiMaterial = material.material.isMultiSupport(); -+ if (isMultiMaterial) { -+ // 贴图在 updateRenderData 才确定下来 -+ // if (texture) this._updateMultiTexId(material, texture); -+ this._texIdDirty = true; -+ } else { -+ material.setProperty('texture', this._frame._texture); -+ } -+ -+ // 根据材质更新 assembler -+ if (this._assembler) { -+ if ((isMultiMaterial && !this._assembler.isMulti) || !isMultiMaterial && this._assembler.isMulti) { -+ RenderComponent.prototype._resetAssembler.call(this); -+ } -+ } -+ } - - BlendFunc.prototype._updateMaterial.call(this); - }, -diff --git a/engine/cocos2d/core/components/CCMotionStreak.js b/engine/cocos2d/core/components/CCMotionStreak.js -index 0b24abf..545c03f 100644 ---- a/engine/cocos2d/core/components/CCMotionStreak.js -+++ b/engine/cocos2d/core/components/CCMotionStreak.js -@@ -160,6 +160,10 @@ var MotionStreak = cc.Class({ - if (this._texture === value) return; - - this._texture = value; -+ -+ // 自动切换材质 -+ this._checkSwitchMaterial(); -+ - this._updateMaterial(); - }, - type: cc.Texture2D, -@@ -209,6 +213,24 @@ var MotionStreak = cc.Class({ - }, - animatable: false, - tooltip: CC_DEV && 'i18n:COMPONENT.motionStreak.fastMode' -+ }, -+ -+ autoSwitchMaterial: { -+ type: RenderComponent.EnableType, -+ default: RenderComponent.EnableType.GLOBAL, -+ }, -+ }, -+ -+ __preload() { -+ this._super(); -+ this._checkSwitchMaterial(); -+ }, -+ -+ _checkSwitchMaterial() { -+ if (this._assembler) { -+ const material = this._materials[0]; -+ if (!material) return; -+ this._assembler.checkAndSwitchMaterial(this, this._texture, material); - } - }, - -@@ -219,7 +241,29 @@ var MotionStreak = cc.Class({ - - _updateMaterial () { - let material = this.getMaterial(0); -- material && material.setProperty('texture', this._texture); -+ -+ // 根据材质更新 uniform -+ const isMultiMaterial = material.material.isMultiSupport(); -+ if (isMultiMaterial) { -+ this._updateMultiTexId(material, this._texture); -+ } else { -+ if (material.getProperty('texture') !== this._texture) { -+ material.setProperty('texture', this._texture); -+ } -+ } -+ -+ // 根据材质更新 assembler -+ if (this._assembler) { -+ if ((isMultiMaterial && !this._assembler.isMulti) || !isMultiMaterial && this._assembler.isMulti) { -+ this._resetAssembler(); -+ } -+ } -+ -+ // texId -+ if (isMultiMaterial && this._texIdDirty) { -+ this._assembler.updateTexId(this); -+ this._texIdDirty = false; -+ } - - BlendFunc.prototype._updateMaterial.call(this); - }, -diff --git a/engine/cocos2d/core/components/CCRenderComponent.js b/engine/cocos2d/core/components/CCRenderComponent.js -index c23fc4d..fb7103a 100644 ---- a/engine/cocos2d/core/components/CCRenderComponent.js -+++ b/engine/cocos2d/core/components/CCRenderComponent.js -@@ -33,6 +33,32 @@ const Material = require('../assets/material/CCMaterial'); - - let _temp_color = new Color(); - -+/** -+ * !#en enable type -+ * !#zh 启用类型 -+ * @enum RenderComponent.EnableType -+ */ -+var EnableType = cc.Enum({ -+ /** -+ * !#en Global. -+ * !#zh 使用全局值 -+ * @property {Number} GLOBAL -+ */ -+ GLOBAL: 0, -+ /** -+ * !#en Enable. -+ * !#zh 开启 -+ * @property {Number} ENABLE -+ */ -+ ENABLE: 1, -+ /** -+ * !#en Disable. -+ * !#zh 关闭 -+ * @property {Number} DISABLE -+ */ -+ DISABLE: 2, -+}); -+ - /** - * !#en - * Base class for components which supports rendering features. -@@ -51,6 +77,10 @@ let RenderComponent = cc.Class({ - disallowMultiple: true - }, - -+ statics: { -+ EnableType: EnableType, -+ }, -+ - properties: { - _materials: { - default: [], -@@ -78,12 +108,16 @@ let RenderComponent = cc.Class({ - - ctor () { - this._vertsDirty = true; -+ this._texIdDirty = true; -+ this._texId = 0; - this._assembler = null; - }, - - _resetAssembler () { - Assembler.init(this); - this._updateColor(); -+ // 切换 Assembler 时,texId 与 vDatas 数据不同步 -+ this._texId = 0; - this.setVertsDirty(); - }, - -@@ -250,7 +284,43 @@ let RenderComponent = cc.Class({ - renderer.material = material; - renderer.cullingMask = cullingMask; - } -- } -+ }, -+ -+ _updateMultiTexId(material, texture) { -+ const multi = material.material.getMultiHandler(); -+ -+ const spTexture = texture; -+ const nSpTexture = spTexture.getImpl(); -+ -+ // 快速检查插槽上的贴图是否相同 -+ // 如果是当作普通材质使用,multi.getTexture(this._texId) !== nSpTexture 会一直为 true -+ const same = this._texId === 0 -+ ? material.getProperty('texture') !== nSpTexture -+ : multi.getTexture(this._texId) !== nSpTexture; -+ -+ if (same) { -+ // 如果材质变体被修改了,则直接跳过位置检查 -+ const isChanged = Object.prototype.hasOwnProperty.call(material._effect._passes['0']._properties, 'texture'); -+ const texId = isChanged ? -1 : multi.getIndex(nSpTexture); -+ -+ if (texId !== -1) { -+ // 插槽位置不对,则更新位置 -+ this._texId = texId; -+ this._texIdDirty = true; -+ } else { -+ // 插槽根本没有该纹理,则修改变体的 texture -+ material.setProperty('texture', spTexture); -+ if (this._texId !== 0) { -+ this._texId = 0; -+ this._texIdDirty = true; -+ } -+ // cc.warn('renderComponent use multi-material but not has valid property.'); -+ } -+ } else { -+ this._texIdDirty = false; -+ } -+ }, -+ - }); - - cc.RenderComponent = module.exports = RenderComponent; -diff --git a/engine/cocos2d/core/components/CCRichText.js b/engine/cocos2d/core/components/CCRichText.js -index af99d65..ae1183e 100644 ---- a/engine/cocos2d/core/components/CCRichText.js -+++ b/engine/cocos2d/core/components/CCRichText.js -@@ -28,6 +28,7 @@ const js = require('../platform/js'); - const macro = require('../platform/CCMacro'); - const textUtils = require('../utils/text-utils'); - const HtmlTextParser = require('../utils/html-text-parser'); -+import MaterialVariant from '../assets/material/material-variant'; - const _htmlTextParser = new HtmlTextParser(); - - const HorizontalAlign = macro.TextAlignment; -@@ -36,6 +37,8 @@ const RichTextChildName = "RICHTEXT_CHILD"; - const RichTextChildImageName = "RICHTEXT_Image_CHILD"; - const CacheMode = cc.Label.CacheMode; - -+const RenderComponent = require('./CCRenderComponent'); -+ - // Returns a function, that, as long as it continues to be invoked, will not - // be triggered. The function will be called after it stops being called for - // N milliseconds. If `immediate` is passed, trigger the function on the -@@ -129,7 +132,7 @@ let RichText = cc.Class({ - editor: CC_EDITOR && { - menu: 'i18n:MAIN_MENU.component.renderers/RichText', - help: 'i18n:COMPONENT.help_url.richtext', -- inspector: 'packages://inspector/inspectors/comps/richtext.js', -+ inspector: 'packages://service-pack/inspectors/comps/richtext.js', - executeInEditMode: true - }, - -@@ -346,6 +349,30 @@ let RichText = cc.Class({ - this.handleTouchEvent ? this._addEventListeners() : this._removeEventListeners(); - } - } -+ }, -+ -+ autoSwitchMaterial: { -+ type: RenderComponent.EnableType, -+ default: RenderComponent.EnableType.GLOBAL, -+ notify: function (oldValue) { -+ if (this.autoSwitchMaterial === oldValue) return; -+ for (let i = 0; i < this._labelSegments.length; i++) { -+ const labelComponent = this._labelSegments[i].getComponent(cc.Label); -+ if (labelComponent) { -+ labelComponent.autoSwitchMaterial = this.autoSwitchMaterial; -+ } -+ const spriteComponent = this._labelSegments[i].getComponent(cc.Sprite); -+ if (spriteComponent) { -+ spriteComponent.autoSwitchMaterial = this.autoSwitchMaterial; -+ } -+ } -+ for (let i = 0; i < this._labelSegmentsCache.length; i++) { -+ const labelComponent = this._labelSegmentsCache[i].getComponent(cc.Label); -+ if (labelComponent) { -+ labelComponent.autoSwitchMaterial = this.autoSwitchMaterial; -+ } -+ } -+ } - } - }, - -@@ -656,6 +683,8 @@ let RichText = cc.Class({ - if (spriteFrame) { - let spriteNode = new cc.PrivateNode(RichTextChildImageName); - let spriteComponent = spriteNode.addComponent(cc.Sprite); -+ -+ spriteComponent.autoSwitchMaterial = this.autoSwitchMaterial; - switch (richTextElement.style.imageAlign) - { - case 'top': -@@ -948,6 +977,7 @@ let RichText = cc.Class({ - - labelComponent.cacheMode = this.cacheMode; - -+ labelComponent.autoSwitchMaterial = this.autoSwitchMaterial; - let isAsset = this.font instanceof cc.Font; - if (isAsset && !this._isSystemFontUsed) { - labelComponent.font = this.font; -diff --git a/engine/cocos2d/core/components/CCSprite.js b/engine/cocos2d/core/components/CCSprite.js -index a265b1a..f0cf757 100644 ---- a/engine/cocos2d/core/components/CCSprite.js -+++ b/engine/cocos2d/core/components/CCSprite.js -@@ -160,7 +160,7 @@ var Sprite = cc.Class({ - editor: CC_EDITOR && { - menu: 'i18n:MAIN_MENU.component.renderers/Sprite', - help: 'i18n:COMPONENT.help_url.sprite', -- inspector: 'packages://inspector/inspectors/comps/sprite.js', -+ inspector: 'packages://service-pack/inspectors/comps/sprite.js', - }, - - properties: { -@@ -383,7 +383,12 @@ var Sprite = cc.Class({ - animatable: false, - type: SizeMode, - tooltip: CC_DEV && 'i18n:COMPONENT.sprite.size_mode' -- } -+ }, -+ -+ autoSwitchMaterial: { -+ type: RenderComponent.EnableType, -+ default: RenderComponent.EnableType.GLOBAL, -+ }, - }, - - statics: { -@@ -449,8 +454,24 @@ var Sprite = cc.Class({ - if (material.getDefine('USE_TEXTURE') !== undefined) { - material.define('USE_TEXTURE', true); - } -- if (material.getProperty('texture') !== texture) { -- material.setProperty('texture', texture); -+ -+ // 根据材质更新 uniform -+ const isMultiMaterial = material.material.isMultiSupport(); -+ if (isMultiMaterial) { -+ // 在 assembler 中进行更新性能会更好,不需要每次 setSpriteFrame 都更新,并且动态图集会导致两次触发 -+ // if (texture) this._updateMultiTexId(material, texture); -+ this._texIdDirty = true; -+ } else { -+ if (material.getProperty('texture') !== texture) { -+ material.setProperty('texture', texture); -+ } -+ } -+ -+ // 根据材质更新 assembler -+ if (this._assembler) { -+ if ((isMultiMaterial && !this._assembler.isMulti) || !isMultiMaterial && this._assembler.isMulti) { -+ this._resetAssembler(); -+ } - } - } - -diff --git a/engine/cocos2d/core/platform/CCMacro.js b/engine/cocos2d/core/platform/CCMacro.js -index dddc686..037ee54 100644 ---- a/engine/cocos2d/core/platform/CCMacro.js -+++ b/engine/cocos2d/core/platform/CCMacro.js -@@ -384,9 +384,9 @@ cc.macro = { - * 是否使用原生的文本渲染机制, 布局和编辑器有差异. - * - * @property {Boolean} ENABLE_NATIVE_TTF_RENDERER -- * @default true -+ * @default false - */ -- ENABLE_NATIVE_TTF_RENDERER: true -+ ENABLE_NATIVE_TTF_RENDERER: false - - }; - -diff --git a/engine/cocos2d/core/renderer/assembler-2d.js b/engine/cocos2d/core/renderer/assembler-2d.js -index 29287a1..8390f28 100644 ---- a/engine/cocos2d/core/renderer/assembler-2d.js -+++ b/engine/cocos2d/core/renderer/assembler-2d.js -@@ -131,22 +131,13 @@ export default class Assembler2D extends Assembler { - } - } - -- packToDynamicAtlas (comp, frame) { -- if (CC_TEST) return; -- -- if (!frame._original && dynamicAtlasManager && frame._texture.packable) { -- let packedFrame = dynamicAtlasManager.insertSpriteFrame(frame); -- if (packedFrame) { -- frame._setDynamicAtlasFrame(packedFrame); -- } -- } -- let material = comp._materials[0]; -- if (!material) return; -- -- if (material.getProperty('texture') !== frame._texture) { -- // texture was packed to dynamic atlas, should update uvs -- comp._vertsDirty = true; -- comp._updateMaterial(); -+ updateTexId(comp) { -+ const texId = comp._texId; -+ let texIdOffset = this.texIdOffset; -+ let floatsPerVert = this.floatsPerVert; -+ let verts = this._renderData.vDatas[0]; -+ for (let i = 0, l = verts.length; i < l; i++) { -+ verts[floatsPerVert * i + texIdOffset] = texId; - } - } - } -@@ -159,6 +150,8 @@ cc.js.addon(Assembler2D.prototype, { - - uvOffset: 2, - colorOffset: 4, -+ -+ isMulti: false, - }); - - cc.Assembler2D = Assembler2D; -diff --git a/engine/cocos2d/core/renderer/assembler.js b/engine/cocos2d/core/renderer/assembler.js -index b2cafd0..a65088b 100644 ---- a/engine/cocos2d/core/renderer/assembler.js -+++ b/engine/cocos2d/core/renderer/assembler.js -@@ -1,5 +1,6 @@ - import { vfmtPosUvColor } from './webgl/vertex-format'; - import assemblerPool from './assembler-pool'; -+import dynamicAtlasManager from './utils/dynamic-atlas/manager'; - - export default class Assembler { - constructor () { -@@ -12,12 +13,64 @@ export default class Assembler { - updateRenderData (comp) { - } - -+ updateRenderDataForSwitchMaterial(comp) { -+ -+ } -+ - fillBuffers (comp, renderer) { - } - - getVfmt () { - return vfmtPosUvColor; - } -+ -+ packDynamicAtlasAndCheckMaterial(comp, frame) { -+ if (CC_TEST) return false; -+ -+ if (!frame._original && dynamicAtlasManager && frame._texture.packable) { -+ let packedFrame = dynamicAtlasManager.insertSpriteFrame(frame); -+ if (packedFrame) { -+ frame._setDynamicAtlasFrame(packedFrame); -+ } -+ } -+ -+ const material = comp._materials[0]; -+ if (!material) return false; -+ -+ // 自动切换材质 -+ if (this.checkAndSwitchMaterial(comp, frame._texture, material)) { -+ return true; -+ } -+ -+ if (material.material.isMultiSupport()) { -+ comp._texIdDirty = true; -+ } else { -+ if (material.getProperty('texture') !== frame._texture) { -+ // texture was packed to dynamic atlas, should update uvs -+ comp._vertsDirty = true; -+ comp._updateMaterial(); -+ } -+ } -+ -+ return false; -+ } -+ -+ checkAndSwitchMaterial(comp, texture, material) { -+ const autoSwitchMaterial = comp.autoSwitchMaterial; -+ if ((cc.sp.autoSwitchMaterial && autoSwitchMaterial === 0) || autoSwitchMaterial === 1) { -+ if (texture._multiMaterial) { -+ if (material.material !== texture._multiMaterial) { -+ comp.setMaterial(0, texture._multiMaterial); -+ // setMaterial 中会置 comp._texIdDirty = true; -+ if (!this.isMulti) { -+ comp._assembler.updateRenderDataForSwitchMaterial(comp); -+ return true; -+ } -+ } -+ } -+ } -+ } -+ - } - - -diff --git a/engine/cocos2d/core/renderer/utils/label/bmfont.js b/engine/cocos2d/core/renderer/utils/label/bmfont.js -index 0b91a27..57951a5 100644 ---- a/engine/cocos2d/core/renderer/utils/label/bmfont.js -+++ b/engine/cocos2d/core/renderer/utils/label/bmfont.js -@@ -84,12 +84,32 @@ export default class BmfontAssembler extends Assembler2D { - _comp = comp; - - this._reserveQuads(comp, comp.string.toString().length); -- this._updateFontFamily(comp); -+ -+ const assemblerChanged = this._updateFontFamily(comp); -+ -+ // 打包到动态图集时可能会切换 Assembler -+ if (!assemblerChanged) { -+ this._updateRenderData(comp); -+ } -+ } -+ -+ _preUpdateRenderData(comp) { -+ _comp = comp; -+ -+ this._reserveQuads(comp, comp.string.toString().length); -+ -+ let fontAsset = comp.font; -+ _spriteFrame = fontAsset.spriteFrame; -+ _fntConfig = fontAsset._fntConfig; -+ shareLabelInfo.fontAtlas = fontAsset._fontDefDictionary; -+ } -+ -+ _updateRenderData(comp) { - this._updateProperties(comp); - this._updateLabelInfo(comp); - this._updateContent(); - this.updateWorldVerts(comp); -- -+ - _comp._actualFontSize = _fontSize; - _comp.node.setContentSize(_contentSize); - -@@ -108,7 +128,7 @@ export default class BmfontAssembler extends Assembler2D { - _fntConfig = fontAsset._fntConfig; - shareLabelInfo.fontAtlas = fontAsset._fontDefDictionary; - -- this.packToDynamicAtlas(comp, _spriteFrame); -+ return this.packDynamicAtlasAndCheckMaterial(comp, _spriteFrame); - } - - _updateLabelInfo() { -diff --git a/engine/cocos2d/core/renderer/utils/label/ttf.js b/engine/cocos2d/core/renderer/utils/label/ttf.js -index 56edd9b..9d85e3f 100644 ---- a/engine/cocos2d/core/renderer/utils/label/ttf.js -+++ b/engine/cocos2d/core/renderer/utils/label/ttf.js -@@ -106,8 +106,15 @@ export default class TTFAssembler extends Assembler2D { - this._calculateLabelFont(); - this._updateLabelDimensions(); - this._updateTexture(comp); -- this._calDynamicAtlas(comp); -+ const assemblerChanged = this._calDynamicAtlas(comp); - -+ // 打包到动态图集时可能会切换 Assembler -+ if (!assemblerChanged) { -+ this._updateRenderData(comp); -+ } -+ } -+ -+ _updateRenderData(comp) { - comp._actualFontSize = _fontSize; - comp.node.setContentSize(_nodeContentSize); - -@@ -336,14 +343,14 @@ export default class TTFAssembler extends Assembler2D { - } - - _calDynamicAtlas (comp) { -- if(comp.cacheMode !== Label.CacheMode.BITMAP) return; -+ if(comp.cacheMode !== Label.CacheMode.BITMAP) return false; - let frame = comp._frame; - // Delete cache in atlas. - deleteFromDynamicAtlas(comp, frame); - if (!frame._original) { - frame.setRect(cc.rect(0, 0, _canvas.width, _canvas.height)); - } -- this.packToDynamicAtlas(comp, frame); -+ return this.packDynamicAtlasAndCheckMaterial(comp, frame); - } - - _updateLabelDimensions () { -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/index.js b/engine/cocos2d/core/renderer/webgl/assemblers/index.js -index 4ffbc1c..e24a556 100644 ---- a/engine/cocos2d/core/renderer/webgl/assemblers/index.js -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/index.js -@@ -24,9 +24,10 @@ - ****************************************************************************/ - - cc.assemblers = {}; -- -+ - require('./sprite'); - require('./mask-assembler'); - require('./graphics'); - require('./label'); - require('./motion-streak'); -+require('./motion-streak-multi'); -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/label/2d-multi/bmfont.js b/engine/cocos2d/core/renderer/webgl/assemblers/label/2d-multi/bmfont.js -new file mode 100644 -index 0000000..3fe3d2e ---- /dev/null -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/label/2d-multi/bmfont.js -@@ -0,0 +1,71 @@ -+/**************************************************************************** -+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. -+ -+ https://www.cocos.com/ -+ -+ Permission is hereby granted, free of charge, to any person obtaining a copy -+ of this software and associated engine source code (the "Software"), a limited, -+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license -+ to use Cocos Creator solely to develop games on your target platforms. You shall -+ not use Cocos Creator software for developing other software or tools that's -+ used for developing games. You are not granted to publish, distribute, -+ sublicense, and/or sell copies of Cocos Creator. -+ -+ The software or tools in this License Agreement are licensed, not sold. -+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. -+ -+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ THE SOFTWARE. -+ ****************************************************************************/ -+ -+import WebglBmfontAssembler from '../2d/bmfont'; -+import { vfmtPosUvColorTexId } from '../../../../webgl/vertex-format'; -+ -+export default class MultiWebglBmfontAssembler extends WebglBmfontAssembler { -+ 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()); -+ } -+ -+ updateRenderData(comp) { -+ super.updateRenderData(comp); -+ -+ if (comp._texIdDirty) { -+ comp._updateMultiTexId(comp.getMaterial(0), comp._frame._texture); -+ } -+ -+ // 不进行 Dirty 判断,文本可能会变化,但是纹理不会变 -+ this.updateTexId(comp); -+ comp._texIdDirty = false; -+ } -+ -+ updateRenderDataForSwitchMaterial(comp) { -+ super._preUpdateRenderData(comp); -+ super._updateRenderData(comp); -+ -+ if (comp._texIdDirty) { -+ comp._updateMultiTexId(comp.getMaterial(0), comp._frame._texture); -+ } -+ -+ // 不进行 Dirty 判断,文本可能会变化,但是纹理不会变 -+ this.updateTexId(comp); -+ comp._texIdDirty = false; -+ } -+} -+ -+MultiWebglBmfontAssembler.prototype.floatsPerVert = 6; -+MultiWebglBmfontAssembler.prototype.texIdOffset = 5; -+MultiWebglBmfontAssembler.prototype.isMulti = true; -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/label/2d-multi/ttf.js b/engine/cocos2d/core/renderer/webgl/assemblers/label/2d-multi/ttf.js -new file mode 100644 -index 0000000..4e63a79 ---- /dev/null -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/label/2d-multi/ttf.js -@@ -0,0 +1,72 @@ -+/**************************************************************************** -+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. -+ -+ https://www.cocos.com/ -+ -+ Permission is hereby granted, free of charge, to any person obtaining a copy -+ of this software and associated engine source code (the "Software"), a limited, -+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license -+ to use Cocos Creator solely to develop games on your target platforms. You shall -+ not use Cocos Creator software for developing other software or tools that's -+ used for developing games. You are not granted to publish, distribute, -+ sublicense, and/or sell copies of Cocos Creator. -+ -+ The software or tools in this License Agreement are licensed, not sold. -+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. -+ -+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ THE SOFTWARE. -+ ****************************************************************************/ -+ -+import WebglTTFAssembler from '../2d/ttf'; -+import { vfmtPosUvColorTexId } from '../../../../webgl/vertex-format'; -+ -+export default class MultiWebglTTFAssembler extends WebglTTFAssembler { -+ initData() { -+ let data = this._renderData; -+ data.createFlexData(0, this.verticesCount, this.indicesCount, this.getVfmt()); -+ const indices = data.iDatas[0]; -+ data.initQuadIndices(indices); -+ } -+ -+ getVfmt() { -+ return vfmtPosUvColorTexId; -+ } -+ -+ getBuffer() { -+ return cc.renderer._handle.getBuffer("mesh", this.getVfmt()); -+ } -+ -+ updateRenderData(comp) { -+ super.updateRenderData(comp); -+ -+ if (comp._texIdDirty) { -+ comp._updateMultiTexId(comp.getMaterial(0), comp._frame._texture); -+ } -+ -+ // 不进行 Dirty 判断,文本可能会变化,但是纹理不会变 -+ this.updateTexId(comp); -+ comp._texIdDirty = false; -+ } -+ -+ updateRenderDataForSwitchMaterial(comp) { -+ super._updateRenderData(comp); -+ -+ if (comp._texIdDirty) { -+ comp._updateMultiTexId(comp.getMaterial(0), comp._frame._texture); -+ } -+ -+ // 不进行 Dirty 判断,文本可能会变化,但是纹理不会变 -+ this.updateTexId(comp); -+ comp._texIdDirty = false; -+ } -+} -+ -+MultiWebglTTFAssembler.prototype.floatsPerVert = 6; -+MultiWebglTTFAssembler.prototype.texIdOffset = 5; -+MultiWebglTTFAssembler.prototype.isMulti = true; -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/label/index.js b/engine/cocos2d/core/renderer/webgl/assemblers/label/index.js -index ad2d511..5e3da64 100644 ---- a/engine/cocos2d/core/renderer/webgl/assemblers/label/index.js -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/label/index.js -@@ -34,6 +34,9 @@ import TTF3D from './3d/ttf'; - import Bmfont3D from './3d/bmfont'; - import Letter3D from './3d/letter'; - -+import TTFMulti from './2d-multi/ttf'; -+import BmfontMulti from './2d-multi/bmfont'; -+ - let NativeTTF = undefined; - if(CC_JSB) { - NativeTTF = require("./2d/nativeTTF"); -@@ -69,10 +72,13 @@ Label._canvasPool = { - Assembler.register(cc.Label, { - getConstructor(label) { - let is3DNode = label.node.is3DNode; -- let ctor = is3DNode ? TTF3D : TTF; -+ const material = label.getMaterials()[0]; -+ let isMultiMaterial = material && material.material.isMultiSupport(); -+ -+ let ctor = is3DNode ? TTF3D : (isMultiMaterial ? TTFMulti : TTF); - - if (label.font instanceof cc.BitmapFont) { -- ctor = is3DNode ? Bmfont3D : Bmfont; -+ ctor = is3DNode ? Bmfont3D : (isMultiMaterial ? BmfontMulti : Bmfont); - } else if (label.cacheMode === Label.CacheMode.CHAR) { - - if(CC_JSB && !is3DNode && !!jsb.LabelRenderer && label.font instanceof cc.TTFFont && label._useNativeTTF()){ -@@ -94,5 +100,8 @@ Assembler.register(cc.Label, { - TTF3D, - Bmfont3D, - Letter3D, -- NativeTTF -+ NativeTTF, -+ -+ TTFMulti, -+ BmfontMulti - }); -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/motion-streak-multi.js b/engine/cocos2d/core/renderer/webgl/assemblers/motion-streak-multi.js -new file mode 100644 -index 0000000..5a41c3b ---- /dev/null -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/motion-streak-multi.js -@@ -0,0 +1,233 @@ -+/**************************************************************************** -+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. -+ -+ https://www.cocos.com/ -+ -+ Permission is hereby granted, free of charge, to any person obtaining a copy -+ of this software and associated engine source code (the "Software"), a limited, -+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license -+ to use Cocos Creator solely to develop games on your target platforms. You shall -+ not use Cocos Creator software for developing other software or tools that's -+ used for developing games. You are not granted to publish, distribute, -+ sublicense, and/or sell copies of Cocos Creator. -+ -+ The software or tools in this License Agreement are licensed, not sold. -+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. -+ -+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ THE SOFTWARE. -+ ****************************************************************************/ -+ -+import MotionStreakAssembler from "./motion-streak"; -+import { vfmtPosUvColorTexId } from '../../webgl/vertex-format'; -+const MotionStreak = require('../../../components/CCMotionStreak'); -+const RenderFlow = require('../../render-flow'); -+ -+function Point(point, dir) { -+ this.point = point || cc.v2(); -+ this.dir = dir || cc.v2(); -+ this.distance = 0; -+ this.time = 0; -+} -+ -+Point.prototype.setPoint = function (x, y) { -+ this.point.x = x; -+ this.point.y = y; -+}; -+ -+Point.prototype.setDir = function (x, y) { -+ this.dir.x = x; -+ this.dir.y = y; -+}; -+ -+let _normal = cc.v2(); -+let _vec2 = cc.v2(); -+ -+function normal(out, dir) { -+ //get perpendicular -+ out.x = -dir.y; -+ out.y = dir.x; -+ return out -+} -+ -+export default class MultiMotionStreakAssembler extends MotionStreakAssembler { -+ initData() { -+ this._renderData.createFlexData(0, 16, (16 - 2) * 3, this.getVfmt()); -+ } -+ -+ getVfmt() { -+ return vfmtPosUvColorTexId; -+ } -+ -+ getBuffer() { -+ return cc.renderer._handle.getBuffer("mesh", this.getVfmt()); -+ } -+ -+ update(comp, dt) { -+ if (CC_EDITOR && !comp.preview) return; -+ -+ let stroke = comp._stroke / 2; -+ -+ let node = comp.node; -+ let matrix = node._worldMatrix.m; -+ let tx = matrix[12], ty = matrix[13]; -+ -+ let points = comp._points; -+ -+ let cur; -+ if (points.length > 1) { -+ let difx = points[0].point.x - tx; -+ let dify = points[0].point.y - ty; -+ if ((difx * difx + dify * dify) < comp.minSeg) { -+ cur = points[0]; -+ } -+ } -+ -+ if (!cur) { -+ cur = new Point(); -+ points.splice(0, 0, cur); -+ } -+ -+ cur.setPoint(tx, ty); -+ cur.time = comp._fadeTime + dt; -+ -+ let verticesCount = 0; -+ let indicesCount = 0; -+ -+ if (points.length < 2) { -+ return; -+ } -+ -+ let color = comp._color, -+ cr = color.r, cg = color.g, cb = color.b, ca = color.a; -+ -+ let prev = points[1]; -+ prev.distance = cur.point.sub(prev.point, _vec2).mag(); -+ _vec2.normalizeSelf(); -+ prev.setDir(_vec2.x, _vec2.y); -+ cur.setDir(_vec2.x, _vec2.y); -+ -+ let flexBuffer = this._renderData._flexBuffer; -+ flexBuffer.reserve(points.length * 2, (points.length - 1) * 6); -+ let vData = flexBuffer.vData; -+ let uintVData = flexBuffer.uintVData; -+ let vertsOffset = 6; -+ -+ let fadeTime = comp._fadeTime; -+ let findLast = false; -+ for (let i = points.length - 1; i >= 0; i--) { -+ let p = points[i]; -+ let point = p.point; -+ let dir = p.dir; -+ p.time -= dt; -+ -+ if (p.time < 0) { -+ points.splice(i, 1); -+ continue; -+ } -+ -+ let progress = p.time / fadeTime; -+ -+ let next = points[i - 1]; -+ if (!findLast) { -+ if (!next) { -+ points.splice(i, 1); -+ continue; -+ } -+ -+ point.x = next.point.x - dir.x * progress; -+ point.y = next.point.y - dir.y * progress; -+ } -+ findLast = true; -+ -+ normal(_normal, dir); -+ -+ -+ let da = progress * ca; -+ let c = ((da << 24) >>> 0) + (cb << 16) + (cg << 8) + cr; -+ -+ let offset = verticesCount * vertsOffset; -+ -+ vData[offset] = point.x + _normal.x * stroke; -+ vData[offset + 1] = point.y + _normal.y * stroke; -+ vData[offset + 2] = 1; -+ vData[offset + 3] = progress; -+ uintVData[offset + 4] = c; -+ vData[offset + 5] = comp._texId; -+ -+ offset += vertsOffset; -+ -+ vData[offset] = point.x - _normal.x * stroke; -+ vData[offset + 1] = point.y - _normal.y * stroke; -+ vData[offset + 2] = 0; -+ vData[offset + 3] = progress; -+ uintVData[offset + 4] = c; -+ vData[offset + 5] = comp._texId; -+ -+ verticesCount += 2; -+ } -+ -+ indicesCount = verticesCount <= 2 ? 0 : (verticesCount - 2) * 3; -+ -+ flexBuffer.used(verticesCount, indicesCount); -+ } -+ -+ fillBuffers(comp, renderer) { -+ let { vData, usedVertices, usedIndices, usedVerticesFloats } = this._renderData._flexBuffer; -+ -+ let buffer = this.getBuffer(renderer); -+ let offsetInfo = buffer.request(usedVertices, usedIndices); -+ -+ // buffer data may be realloc, need get reference after request. -+ -+ // fill vertices -+ let vertexOffset = offsetInfo.byteOffset >> 2, -+ vbuf = buffer._vData; -+ -+ if (vData.length + vertexOffset > vbuf.length) { -+ vbuf.set(vData.subarray(0, usedVerticesFloats), vertexOffset); -+ } -+ else { -+ vbuf.set(vData, vertexOffset); -+ } -+ -+ // fill indices -+ let ibuf = buffer._iData, -+ indiceOffset = offsetInfo.indiceOffset, -+ vertexId = offsetInfo.vertexOffset; -+ -+ // index buffer -+ for (let i = 0, l = usedVertices; i < l; i += 2) { -+ let start = vertexId + i; -+ ibuf[indiceOffset++] = start; -+ ibuf[indiceOffset++] = start + 2; -+ ibuf[indiceOffset++] = start + 1; -+ ibuf[indiceOffset++] = start + 1; -+ ibuf[indiceOffset++] = start + 2; -+ ibuf[indiceOffset++] = start + 3; -+ } -+ -+ comp.node._renderFlag |= RenderFlow.FLAG_UPDATE_RENDER_DATA; -+ } -+ -+} -+ -+MotionStreakAssembler.register(MotionStreak, { -+ getConstructor(comp) { -+ const material = comp.getMaterials()[0]; -+ let isMultiMaterial = material && material.material.isMultiSupport(); -+ return isMultiMaterial ? MultiMotionStreakAssembler : MotionStreakAssembler; -+ }, -+ -+ MotionStreakAssembler, -+ MultiMotionStreakAssembler -+}); -+ -+MultiMotionStreakAssembler.prototype.floatsPerVert = 6; -+MultiMotionStreakAssembler.prototype.texIdOffset = 5; -+MultiMotionStreakAssembler.prototype.isMulti = true; -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/motion-streak.js b/engine/cocos2d/core/renderer/webgl/assemblers/motion-streak.js -index d3161f8..8f40585 100644 ---- a/engine/cocos2d/core/renderer/webgl/assemblers/motion-streak.js -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/motion-streak.js -@@ -25,7 +25,6 @@ - - import Assembler2D from '../../assembler-2d'; - --const MotionStreak = require('../../../components/CCMotionStreak'); - const RenderFlow = require('../../render-flow'); - - function Point (point, dir) { -@@ -226,5 +225,3 @@ export default class MotionStreakAssembler extends Assembler2D { - comp.node._renderFlag |= RenderFlow.FLAG_UPDATE_RENDER_DATA; - } - } -- --MotionStreakAssembler.register(MotionStreak, MotionStreakAssembler); -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/bar-filled.js b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/bar-filled.js -new file mode 100644 -index 0000000..7bbfb6c ---- /dev/null -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/bar-filled.js -@@ -0,0 +1,99 @@ -+/**************************************************************************** -+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. -+ -+ https://www.cocos.com/ -+ -+ Permission is hereby granted, free of charge, to any person obtaining a copy -+ of this software and associated engine source code (the "Software"), a limited, -+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license -+ to use Cocos Creator solely to develop games on your target platforms. You shall -+ not use Cocos Creator software for developing other software or tools that's -+ used for developing games. You are not granted to publish, distribute, -+ sublicense, and/or sell copies of Cocos Creator. -+ -+ The software or tools in this License Agreement are licensed, not sold. -+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. -+ -+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ THE SOFTWARE. -+ ****************************************************************************/ -+ -+import { vfmtPosUvColorTexId } from '../../../../webgl/vertex-format'; -+import BarFilledAssembler from '../2d/bar-filled'; -+ -+export default class BarFilledAssemblerMulti extends BarFilledAssembler { -+ initData() { -+ let data = this._renderData; -+ data.createFlexData(0, this.verticesCount, this.indicesCount, this.getVfmt()); -+ const indices = data.iDatas[0]; -+ data.initQuadIndices(indices); -+ } -+ -+ getVfmt() { -+ return vfmtPosUvColorTexId; -+ } -+ -+ getBuffer() { -+ return cc.renderer._handle.getBuffer("mesh", this.getVfmt()); -+ } -+ -+ updateRenderData (sprite) { -+ super.updateRenderData(sprite); -+ -+ if (sprite._texIdDirty) { -+ sprite._updateMultiTexId(sprite.getMaterial(0), sprite._spriteFrame._texture); -+ if (sprite._texIdDirty) { -+ this.updateTexId(sprite); -+ sprite._texIdDirty = false; -+ } -+ } -+ } -+ -+ updateRenderDataForSwitchMaterial(sprite) { -+ if (sprite._vertsDirty) { -+ let fillStart = sprite._fillStart; -+ let fillRange = sprite._fillRange; -+ -+ if (fillRange < 0) { -+ fillStart += fillRange; -+ fillRange = -fillRange; -+ } -+ -+ fillRange = fillStart + fillRange; -+ -+ fillStart = fillStart > 1.0 ? 1.0 : fillStart; -+ fillStart = fillStart < 0.0 ? 0.0 : fillStart; -+ -+ fillRange = fillRange > 1.0 ? 1.0 : fillRange; -+ fillRange = fillRange < 0.0 ? 0.0 : fillRange; -+ fillRange = fillRange - fillStart; -+ fillRange = fillRange < 0 ? 0 : fillRange; -+ -+ let fillEnd = fillStart + fillRange; -+ fillEnd = fillEnd > 1 ? 1 : fillEnd; -+ -+ this.updateUVs(sprite, fillStart, fillEnd); -+ this.updateVerts(sprite, fillStart, fillEnd); -+ -+ sprite._vertsDirty = false; -+ } -+ -+ if (sprite._texIdDirty) { -+ sprite._updateMultiTexId(sprite.getMaterial(0), sprite._spriteFrame._texture); -+ if (sprite._texIdDirty) { -+ this.updateTexId(sprite); -+ sprite._texIdDirty = false; -+ } -+ } -+ } -+ -+} -+ -+BarFilledAssemblerMulti.prototype.floatsPerVert = 6; -+BarFilledAssemblerMulti.prototype.texIdOffset = 5; -+BarFilledAssemblerMulti.prototype.isMulti = true; -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/mesh.js b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/mesh.js -new file mode 100644 -index 0000000..1166031 ---- /dev/null -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/mesh.js -@@ -0,0 +1,94 @@ -+/**************************************************************************** -+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. -+ -+ https://www.cocos.com/ -+ -+ Permission is hereby granted, free of charge, to any person obtaining a copy -+ of this software and associated engine source code (the "Software"), a limited, -+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license -+ to use Cocos Creator solely to develop games on your target platforms. You shall -+ not use Cocos Creator software for developing other software or tools that's -+ used for developing games. You are not granted to publish, distribute, -+ sublicense, and/or sell copies of Cocos Creator. -+ -+ The software or tools in this License Agreement are licensed, not sold. -+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. -+ -+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ THE SOFTWARE. -+ ****************************************************************************/ -+ -+import { vfmtPosUvColorTexId } from '../../../../webgl/vertex-format'; -+import MeshSpriteAssembler from '../2d/mesh'; -+ -+export default class MultiMeshSpriteAssembler extends MeshSpriteAssembler { -+ getVfmt() { -+ return vfmtPosUvColorTexId; -+ } -+ -+ getBuffer() { -+ return cc.renderer._handle.getBuffer("mesh", this.getVfmt()); -+ } -+ -+ updateRenderData(sprite) { -+ let frame = sprite.spriteFrame; -+ -+ super.updateRenderData(sprite); -+ -+ if (frame) { -+ if (sprite._texIdDirty) { -+ sprite._updateMultiTexId(sprite.getMaterial(0), frame._texture); -+ } -+ -+ // 不进行 Dirty 判断,Mesh 可能会变化,但是纹理不会变 -+ this.updateTexId(sprite); -+ sprite._texIdDirty = false; -+ } -+ } -+ -+ updateRenderDataForSwitchMaterial(sprite) { -+ let frame = sprite.spriteFrame; -+ -+ if (frame) { -+ let vertices = frame.vertices; -+ if (vertices) { -+ this.verticesCount = vertices.x.length; -+ this.indicesCount = vertices.triangles.length; -+ -+ let renderData = this._renderData; -+ let flexBuffer = renderData._flexBuffer; -+ if (flexBuffer.reserve(this.verticesCount, this.indicesCount)) { -+ this.updateColor(sprite); -+ sprite._vertsDirty = true; -+ } -+ flexBuffer.used(this.verticesCount, this.indicesCount); -+ -+ this.updateIndices(vertices.triangles); -+ -+ if (sprite._vertsDirty) { -+ this.updateUVs(sprite); -+ this.updateVerts(sprite); -+ this.updateWorldVerts(sprite); -+ sprite._vertsDirty = false; -+ } -+ } -+ } -+ -+ if (sprite._texIdDirty) { -+ sprite._updateMultiTexId(sprite.getMaterial(0), frame._texture); -+ } -+ -+ // 不进行 Dirty 判断,Mesh 可能会变化,但是纹理不会变 -+ this.updateTexId(sprite); -+ sprite._texIdDirty = false; -+ } -+} -+ -+MultiMeshSpriteAssembler.prototype.floatsPerVert = 6; -+MultiMeshSpriteAssembler.prototype.texIdOffset = 5; -+MultiMeshSpriteAssembler.prototype.isMulti = true; -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/radial-filled.js b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/radial-filled.js -new file mode 100644 -index 0000000..70f18d4 ---- /dev/null -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/radial-filled.js -@@ -0,0 +1,70 @@ -+/**************************************************************************** -+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. -+ -+ https://www.cocos.com/ -+ -+ Permission is hereby granted, free of charge, to any person obtaining a copy -+ of this software and associated engine source code (the "Software"), a limited, -+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license -+ to use Cocos Creator solely to develop games on your target platforms. You shall -+ not use Cocos Creator software for developing other software or tools that's -+ used for developing games. You are not granted to publish, distribute, -+ sublicense, and/or sell copies of Cocos Creator. -+ -+ The software or tools in this License Agreement are licensed, not sold. -+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. -+ -+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ THE SOFTWARE. -+ ****************************************************************************/ -+ -+import { vfmtPosUvColorTexId } from '../../../../webgl/vertex-format'; -+import RadialFilledAssembler from '../2d/radial-filled'; -+ -+export default class MultiRadialFilledAssembler extends RadialFilledAssembler { -+ initData (sprite) { -+ this._renderData.createFlexData(0, 4, 6, this.getVfmt()); -+ this.updateIndices(); -+ } -+ -+ getVfmt() { -+ return vfmtPosUvColorTexId; -+ } -+ -+ getBuffer() { -+ return cc.renderer._handle.getBuffer("mesh", this.getVfmt()); -+ } -+ -+ updateRenderData (sprite) { -+ super.updateRenderData(sprite); -+ -+ if (sprite._texIdDirty) { -+ sprite._updateMultiTexId(sprite.getMaterial(0), sprite.spriteFrame._texture); -+ } -+ -+ // 不进行 Dirty 判断,Mesh 可能会变化,但是纹理不会变 -+ this.updateTexId(sprite); -+ sprite._texIdDirty = false; -+ } -+ -+ updateRenderDataForSwitchMaterial(sprite) { -+ this._updateRenderData(sprite); -+ -+ if (sprite._texIdDirty) { -+ sprite._updateMultiTexId(sprite.getMaterial(0), sprite.spriteFrame._texture); -+ } -+ -+ // 不进行 Dirty 判断,Mesh 可能会变化,但是纹理不会变 -+ this.updateTexId(sprite); -+ sprite._texIdDirty = false; -+ } -+} -+ -+MultiRadialFilledAssembler.prototype.floatsPerVert = 6; -+MultiRadialFilledAssembler.prototype.texIdOffset = 5; -+MultiRadialFilledAssembler.prototype.isMulti = true; -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/simple.js b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/simple.js -new file mode 100644 -index 0000000..6e91a55 ---- /dev/null -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/simple.js -@@ -0,0 +1,76 @@ -+/**************************************************************************** -+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. -+ -+ https://www.cocos.com/ -+ -+ Permission is hereby granted, free of charge, to any person obtaining a copy -+ of this software and associated engine source code (the "Software"), a limited, -+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license -+ to use Cocos Creator solely to develop games on your target platforms. You shall -+ not use Cocos Creator software for developing other software or tools that's -+ used for developing games. You are not granted to publish, distribute, -+ sublicense, and/or sell copies of Cocos Creator. -+ -+ The software or tools in this License Agreement are licensed, not sold. -+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. -+ -+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ THE SOFTWARE. -+ ****************************************************************************/ -+ -+import { vfmtPosUvColorTexId } from '../../../../webgl/vertex-format'; -+import SimpleSpriteAssembler from '../2d/simple'; -+ -+export default class MultiSimpleSpriteAssembler extends SimpleSpriteAssembler { -+ initData() { -+ let data = this._renderData; -+ data.createFlexData(0, this.verticesCount, this.indicesCount, this.getVfmt()); -+ const indices = data.iDatas[0]; -+ data.initQuadIndices(indices); -+ } -+ -+ getVfmt() { -+ return vfmtPosUvColorTexId; -+ } -+ -+ getBuffer() { -+ return cc.renderer._handle.getBuffer("mesh", this.getVfmt()); -+ } -+ -+ updateRenderData (sprite) { -+ super.updateRenderData(sprite); -+ -+ if (sprite._texIdDirty) { -+ sprite._updateMultiTexId(sprite.getMaterial(0), sprite._spriteFrame._texture); -+ if (sprite._texIdDirty) { -+ this.updateTexId(sprite); -+ sprite._texIdDirty = false; -+ } -+ } -+ } -+ -+ updateRenderDataForSwitchMaterial(sprite) { -+ if (sprite._vertsDirty) { -+ this.updateUVs(sprite); -+ this.updateVerts(sprite); -+ sprite._vertsDirty = false; -+ } -+ -+ if (sprite._texIdDirty) { -+ sprite._updateMultiTexId(sprite.getMaterial(0), sprite._spriteFrame._texture); -+ if (sprite._texIdDirty) { -+ this.updateTexId(sprite); -+ sprite._texIdDirty = false; -+ } -+ } -+ } -+} -+ -+MultiSimpleSpriteAssembler.prototype.floatsPerVert = 6; -+MultiSimpleSpriteAssembler.prototype.texIdOffset = 5; -+MultiSimpleSpriteAssembler.prototype.isMulti = true; -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/sliced.js b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/sliced.js -new file mode 100644 -index 0000000..ec51f02 ---- /dev/null -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/sliced.js -@@ -0,0 +1,89 @@ -+/**************************************************************************** -+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. -+ -+ http://www.cocos.com -+ -+ Permission is hereby granted, free of charge, to any person obtaining a copy -+ of this software and associated engine source code (the "Software"), a limited, -+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license -+ to use Cocos Creator solely to develop games on your target platforms. You shall -+ not use Cocos Creator software for developing other software or tools that's -+ used for developing games. You are not granted to publish, distribute, -+ sublicense, and/or sell copies of Cocos Creator. -+ -+ The software or tools in this License Agreement are licensed, not sold. -+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. -+ -+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ THE SOFTWARE. -+ ****************************************************************************/ -+ -+import { vfmtPosUvColorTexId } from '../../../../webgl/vertex-format'; -+import SlicedAssembler from '../2d/sliced'; -+ -+export default class MultiSlicedAssembler extends SlicedAssembler { -+ initData (sprite) { -+ if (this._renderData.meshCount > 0) return; -+ this._renderData.createFlexData(0, this.verticesCount, this.indicesCount, this.getVfmt()); -+ -+ let indices = this._renderData.iDatas[0]; -+ let indexOffset = 0; -+ for (let r = 0; r < 3; ++r) { -+ for (let c = 0; c < 3; ++c) { -+ let start = r * 4 + c; -+ indices[indexOffset++] = start; -+ indices[indexOffset++] = start + 1; -+ indices[indexOffset++] = start + 4; -+ indices[indexOffset++] = start + 1; -+ indices[indexOffset++] = start + 5; -+ indices[indexOffset++] = start + 4; -+ } -+ } -+ } -+ -+ getVfmt() { -+ return vfmtPosUvColorTexId; -+ } -+ -+ getBuffer() { -+ return cc.renderer._handle.getBuffer("mesh", this.getVfmt()); -+ } -+ -+ updateRenderData (sprite) { -+ super.updateRenderData(sprite); -+ -+ if (sprite._texIdDirty) { -+ sprite._updateMultiTexId(sprite.getMaterial(0), sprite._spriteFrame._texture); -+ if (sprite._texIdDirty) { -+ this.updateTexId(sprite); -+ sprite._texIdDirty = false; -+ } -+ } -+ } -+ -+ updateRenderDataForSwitchMaterial(sprite) { -+ if (sprite._vertsDirty) { -+ this.updateUVs(sprite); -+ this.updateVerts(sprite); -+ sprite._vertsDirty = false; -+ } -+ -+ if (sprite._texIdDirty) { -+ sprite._updateMultiTexId(sprite.getMaterial(0), sprite._spriteFrame._texture); -+ if (sprite._texIdDirty) { -+ this.updateTexId(sprite); -+ sprite._texIdDirty = false; -+ } -+ } -+ } -+ -+} -+ -+MultiSlicedAssembler.prototype.floatsPerVert = 6; -+MultiSlicedAssembler.prototype.texIdOffset = 5; -+MultiSlicedAssembler.prototype.isMulti = true; -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/tiled.js b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/tiled.js -new file mode 100644 -index 0000000..9b170b2 ---- /dev/null -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d-multi/tiled.js -@@ -0,0 +1,99 @@ -+/**************************************************************************** -+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. -+ -+ https://www.cocos.com/ -+ -+ Permission is hereby granted, free of charge, to any person obtaining a copy -+ of this software and associated engine source code (the "Software"), a limited, -+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license -+ to use Cocos Creator solely to develop games on your target platforms. You shall -+ not use Cocos Creator software for developing other software or tools that's -+ used for developing games. You are not granted to publish, distribute, -+ sublicense, and/or sell copies of Cocos Creator. -+ -+ The software or tools in this License Agreement are licensed, not sold. -+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. -+ -+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ THE SOFTWARE. -+ ****************************************************************************/ -+ -+import { vfmtPosUvColorTexId } from '../../../../webgl/vertex-format'; -+import TiledAssembler from '../2d/tiled'; -+ -+export default class MultiTiledAssembler extends TiledAssembler { -+ getVfmt() { -+ return vfmtPosUvColorTexId; -+ } -+ -+ getBuffer() { -+ return cc.renderer._handle.getBuffer("mesh", this.getVfmt()); -+ } -+ -+ updateRenderData(sprite) { -+ super.updateRenderData(sprite); -+ -+ if (sprite._texIdDirty) { -+ sprite._updateMultiTexId(sprite.getMaterial(0), sprite.spriteFrame._texture); -+ } -+ -+ // 不进行 Dirty 判断,Mesh 可能会变化,但是纹理不会变 -+ this.updateTexId(sprite); -+ sprite._texIdDirty = false; -+ } -+ -+ updateRenderDataForSwitchMaterial(sprite) { -+ let frame = sprite._spriteFrame; -+ let node = sprite.node; -+ -+ let contentWidth = this.contentWidth = Math.abs(node.width); -+ let contentHeight = this.contentHeight = Math.abs(node.height); -+ let rect = frame._rect; -+ let leftWidth = frame.insetLeft, rightWidth = frame.insetRight, centerWidth = rect.width - leftWidth - rightWidth, -+ topHeight = frame.insetTop, bottomHeight = frame.insetBottom, centerHeight = rect.height - topHeight - bottomHeight; -+ this.sizableWidth = contentWidth - leftWidth - rightWidth; -+ this.sizableHeight = contentHeight - topHeight - bottomHeight; -+ this.sizableWidth = this.sizableWidth > 0 ? this.sizableWidth : 0; -+ this.sizableHeight = this.sizableHeight > 0 ? this.sizableHeight : 0; -+ let hRepeat = this.hRepeat = centerWidth === 0 ? this.sizableWidth : this.sizableWidth / centerWidth; -+ let vRepeat = this.vRepeat = centerHeight === 0 ? this.sizableHeight : this.sizableHeight / centerHeight; -+ let row = this.row = Math.ceil(vRepeat + 2); -+ let col = this.col = Math.ceil(hRepeat + 2); -+ -+ // update data property -+ let count = row * col; -+ this.verticesCount = count * 4; -+ this.indicesCount = count * 6; -+ -+ let renderData = this._renderData; -+ let flexBuffer = renderData._flexBuffer; -+ if (flexBuffer.reserve(this.verticesCount, this.indicesCount)) { -+ this._updateIndices(); -+ this.updateColor(sprite); -+ } -+ flexBuffer.used(this.verticesCount, this.indicesCount); -+ -+ if (sprite._vertsDirty) { -+ this.updateUVs(sprite); -+ this.updateVerts(sprite); -+ sprite._vertsDirty = false; -+ } -+ -+ if (sprite._texIdDirty) { -+ sprite._updateMultiTexId(sprite.getMaterial(0), sprite.spriteFrame._texture); -+ } -+ -+ // 不进行 Dirty 判断,Mesh 可能会变化,但是纹理不会变 -+ this.updateTexId(sprite); -+ sprite._texIdDirty = false; -+ } -+} -+ -+MultiTiledAssembler.prototype.floatsPerVert = 6; -+MultiTiledAssembler.prototype.texIdOffset = 5; -+MultiTiledAssembler.prototype.isMulti = true; -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/bar-filled.js b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/bar-filled.js -index 34d8af7..5622c2e 100644 ---- a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/bar-filled.js -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/bar-filled.js -@@ -31,37 +31,38 @@ const FillType = Sprite.FillType; - export default class BarFilledAssembler extends Assembler2D { - updateRenderData (sprite) { - let frame = sprite._spriteFrame; -- this.packToDynamicAtlas(sprite, frame); -+ const assemblerChanged = this.packDynamicAtlasAndCheckMaterial(sprite, frame); - -- if (!sprite._vertsDirty) { -- return; -- } -- -- let fillStart = sprite._fillStart; -- let fillRange = sprite._fillRange; -+ // 打包到动态图集时可能会切换 Assembler -+ if (!assemblerChanged) { -+ if (sprite._vertsDirty) { -+ let fillStart = sprite._fillStart; -+ let fillRange = sprite._fillRange; - -- if (fillRange < 0) { -- fillStart += fillRange; -- fillRange = -fillRange; -- } -+ if (fillRange < 0) { -+ fillStart += fillRange; -+ fillRange = -fillRange; -+ } - -- fillRange = fillStart + fillRange; -+ fillRange = fillStart + fillRange; - -- fillStart = fillStart > 1.0 ? 1.0 : fillStart; -- fillStart = fillStart < 0.0 ? 0.0 : fillStart; -+ fillStart = fillStart > 1.0 ? 1.0 : fillStart; -+ fillStart = fillStart < 0.0 ? 0.0 : fillStart; - -- fillRange = fillRange > 1.0 ? 1.0 : fillRange; -- fillRange = fillRange < 0.0 ? 0.0 : fillRange; -- fillRange = fillRange - fillStart; -- fillRange = fillRange < 0 ? 0 : fillRange; -+ fillRange = fillRange > 1.0 ? 1.0 : fillRange; -+ fillRange = fillRange < 0.0 ? 0.0 : fillRange; -+ fillRange = fillRange - fillStart; -+ fillRange = fillRange < 0 ? 0 : fillRange; - -- let fillEnd = fillStart + fillRange; -- fillEnd = fillEnd > 1 ? 1 : fillEnd; -+ let fillEnd = fillStart + fillRange; -+ fillEnd = fillEnd > 1 ? 1 : fillEnd; - -- this.updateUVs(sprite, fillStart, fillEnd); -- this.updateVerts(sprite, fillStart, fillEnd); -+ this.updateUVs(sprite, fillStart, fillEnd); -+ this.updateVerts(sprite, fillStart, fillEnd); - -- sprite._vertsDirty = false; -+ sprite._vertsDirty = false; -+ } -+ } - } - - updateUVs (sprite, fillStart, fillEnd) { -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/mesh.js b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/mesh.js -index a2571ca..8b8b934 100644 ---- a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/mesh.js -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/mesh.js -@@ -31,30 +31,34 @@ export default class MeshSpriteAssembler extends Assembler2D { - } - - updateRenderData (sprite) { -- this.packToDynamicAtlas(sprite, sprite._spriteFrame); -- - let frame = sprite.spriteFrame; -- if (frame) { -- let vertices = frame.vertices; -- if (vertices) { -- this.verticesCount = vertices.x.length; -- this.indicesCount = vertices.triangles.length; -- -- let renderData = this._renderData; -- let flexBuffer = renderData._flexBuffer; -- if (flexBuffer.reserve(this.verticesCount, this.indicesCount)) { -- this.updateColor(sprite); -- sprite._vertsDirty = true; -- } -- flexBuffer.used(this.verticesCount, this.indicesCount); -- -- this.updateIndices(vertices.triangles); - -- if (sprite._vertsDirty) { -- this.updateUVs(sprite); -- this.updateVerts(sprite); -- this.updateWorldVerts(sprite); -- sprite._vertsDirty = false; -+ const assemblerChanged = this.packDynamicAtlasAndCheckMaterial(sprite, frame); -+ -+ // 打包到动态图集时可能会切换 Assembler -+ if (!assemblerChanged) { -+ if (frame) { -+ let vertices = frame.vertices; -+ if (vertices) { -+ this.verticesCount = vertices.x.length; -+ this.indicesCount = vertices.triangles.length; -+ -+ let renderData = this._renderData; -+ let flexBuffer = renderData._flexBuffer; -+ if (flexBuffer.reserve(this.verticesCount, this.indicesCount)) { -+ this.updateColor(sprite); -+ sprite._vertsDirty = true; -+ } -+ flexBuffer.used(this.verticesCount, this.indicesCount); -+ -+ this.updateIndices(vertices.triangles); -+ -+ if (sprite._vertsDirty) { -+ this.updateUVs(sprite); -+ this.updateVerts(sprite); -+ this.updateWorldVerts(sprite); -+ sprite._vertsDirty = false; -+ } - } - } - } -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/radial-filled.js b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/radial-filled.js -index 6bedde3..da5342d 100644 ---- a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/radial-filled.js -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/radial-filled.js -@@ -179,7 +179,16 @@ export default class RadialFilledAssembler extends Assembler2D { - super.updateRenderData(sprite); - - let frame = sprite.spriteFrame; -- this.packToDynamicAtlas(sprite, frame); -+ const assemblerChanged = this.packDynamicAtlasAndCheckMaterial(sprite, frame); -+ -+ // 打包到动态图集时可能会切换 Assembler -+ if (!assemblerChanged) { -+ this._updateRenderData(sprite); -+ } -+ } -+ -+ _updateRenderData(sprite) { -+ let frame = sprite.spriteFrame; - - if (sprite._vertsDirty) { - let fillStart = sprite._fillStart; -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/simple.js b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/simple.js -index 939e7b1..178b70a 100644 ---- a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/simple.js -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/simple.js -@@ -27,12 +27,15 @@ import Assembler2D from '../../../../assembler-2d'; - - export default class SimpleSpriteAssembler extends Assembler2D { - updateRenderData (sprite) { -- this.packToDynamicAtlas(sprite, sprite._spriteFrame); -+ const assemblerChanged = this.packDynamicAtlasAndCheckMaterial(sprite, sprite._spriteFrame); - -- if (sprite._vertsDirty) { -- this.updateUVs(sprite); -- this.updateVerts(sprite); -- sprite._vertsDirty = false; -+ // 打包到动态图集时可能会切换 Assembler -+ if (!assemblerChanged) { -+ if (sprite._vertsDirty) { -+ this.updateUVs(sprite); -+ this.updateVerts(sprite); -+ sprite._vertsDirty = false; -+ } - } - } - -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/sliced.js b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/sliced.js -index 9013a9b..69b3c4f 100644 ---- a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/sliced.js -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/sliced.js -@@ -52,12 +52,15 @@ export default class SlicedAssembler extends Assembler2D { - - updateRenderData (sprite) { - let frame = sprite._spriteFrame; -- this.packToDynamicAtlas(sprite, frame); -- -- if (sprite._vertsDirty) { -- this.updateUVs(sprite); -- this.updateVerts(sprite); -- sprite._vertsDirty = false; -+ const assemblerChanged = this.packDynamicAtlasAndCheckMaterial(sprite, frame); -+ -+ // 打包到动态图集时可能会切换 Assembler -+ if (!assemblerChanged) { -+ if (sprite._vertsDirty) { -+ this.updateUVs(sprite); -+ this.updateVerts(sprite); -+ sprite._vertsDirty = false; -+ } - } - } - -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/tiled.js b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/tiled.js -index 5028e8b..b0c0296 100644 ---- a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/tiled.js -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/2d/tiled.js -@@ -59,41 +59,44 @@ export default class TiledAssembler extends Assembler2D { - - updateRenderData (sprite) { - let frame = sprite._spriteFrame; -- this.packToDynamicAtlas(sprite, frame); -+ const assemblerChanged = this.packDynamicAtlasAndCheckMaterial(sprite, frame); - -- let node = sprite.node; -+ // 打包到动态图集时可能会切换 Assembler -+ if (!assemblerChanged) { -+ let node = sprite.node; - -- let contentWidth = this.contentWidth = Math.abs(node.width); -- let contentHeight = this.contentHeight = Math.abs(node.height); -- let rect = frame._rect; -- let leftWidth = frame.insetLeft, rightWidth = frame.insetRight, centerWidth = rect.width - leftWidth - rightWidth, -- topHeight = frame.insetTop, bottomHeight = frame.insetBottom, centerHeight = rect.height - topHeight - bottomHeight; -- this.sizableWidth = contentWidth - leftWidth - rightWidth; -- this.sizableHeight = contentHeight - topHeight - bottomHeight; -- this.sizableWidth = this.sizableWidth > 0 ? this.sizableWidth : 0; -- this.sizableHeight = this.sizableHeight > 0 ? this.sizableHeight : 0; -- let hRepeat = this.hRepeat = centerWidth === 0 ? this.sizableWidth : this.sizableWidth / centerWidth; -- let vRepeat = this.vRepeat = centerHeight === 0 ? this.sizableHeight : this.sizableHeight / centerHeight; -- let row = this.row = Math.ceil(vRepeat + 2); -- let col = this.col = Math.ceil(hRepeat + 2); -+ let contentWidth = this.contentWidth = Math.abs(node.width); -+ let contentHeight = this.contentHeight = Math.abs(node.height); -+ let rect = frame._rect; -+ let leftWidth = frame.insetLeft, rightWidth = frame.insetRight, centerWidth = rect.width - leftWidth - rightWidth, -+ topHeight = frame.insetTop, bottomHeight = frame.insetBottom, centerHeight = rect.height - topHeight - bottomHeight; -+ this.sizableWidth = contentWidth - leftWidth - rightWidth; -+ this.sizableHeight = contentHeight - topHeight - bottomHeight; -+ this.sizableWidth = this.sizableWidth > 0 ? this.sizableWidth : 0; -+ this.sizableHeight = this.sizableHeight > 0 ? this.sizableHeight : 0; -+ let hRepeat = this.hRepeat = centerWidth === 0 ? this.sizableWidth : this.sizableWidth / centerWidth; -+ let vRepeat = this.vRepeat = centerHeight === 0 ? this.sizableHeight : this.sizableHeight / centerHeight; -+ let row = this.row = Math.ceil(vRepeat + 2); -+ let col = this.col = Math.ceil(hRepeat + 2); - -- // update data property -- let count = row * col; -- this.verticesCount = count * 4; -- this.indicesCount = count * 6; -+ // update data property -+ let count = row * col; -+ this.verticesCount = count * 4; -+ this.indicesCount = count * 6; - -- let renderData = this._renderData; -- let flexBuffer = renderData._flexBuffer; -- if (flexBuffer.reserve(this.verticesCount, this.indicesCount)) { -- this._updateIndices(); -- this.updateColor(sprite); -- } -- flexBuffer.used(this.verticesCount, this.indicesCount); -+ let renderData = this._renderData; -+ let flexBuffer = renderData._flexBuffer; -+ if (flexBuffer.reserve(this.verticesCount, this.indicesCount)) { -+ this._updateIndices(); -+ this.updateColor(sprite); -+ } -+ flexBuffer.used(this.verticesCount, this.indicesCount); - -- if (sprite._vertsDirty) { -- this.updateUVs(sprite); -- this.updateVerts(sprite); -- sprite._vertsDirty = false; -+ if (sprite._vertsDirty) { -+ this.updateUVs(sprite); -+ this.updateVerts(sprite); -+ sprite._vertsDirty = false; -+ } - } - } - -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/index.js b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/index.js -index 885ddc4..de11d9c 100644 ---- a/engine/cocos2d/core/renderer/webgl/assemblers/sprite/index.js -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/sprite/index.js -@@ -15,27 +15,36 @@ import RadialFilled3D from "./3d/radial-filled"; - import BarFilled3D from "./3d/bar-filled"; - import Mesh3D from './3d/mesh'; - -+import SimpleMulti from "./2d-multi/simple"; -+import SlicedMulti from "./2d-multi/sliced"; -+import TiledMulti from "./2d-multi/tiled"; -+import RadialFilledMulti from "./2d-multi/radial-filled"; -+import BarFilledMulti from "./2d-multi/bar-filled"; -+import MeshMulti from "./2d-multi/mesh"; -+ - let ctor = { - getConstructor(sprite) { - let is3DNode = sprite.node.is3DNode; -+ const material = sprite.getMaterials()[0]; -+ let isMultiMaterial = material && material.material.isMultiSupport(); - -- let ctor = is3DNode ? Simple3D : Simple; -+ let ctor = is3DNode ? Simple3D : (isMultiMaterial ? SimpleMulti : Simple); - switch (sprite.type) { - case Type.SLICED: -- ctor = is3DNode ? Sliced3D : Sliced; -+ ctor = is3DNode ? Sliced3D : (isMultiMaterial ? SlicedMulti : Sliced); - break; - case Type.TILED: -- ctor = is3DNode ? Tiled3D : Tiled; -+ ctor = is3DNode ? Tiled3D : (isMultiMaterial ? TiledMulti : Tiled); - break; - case Type.FILLED: - if (sprite._fillType === FillType.RADIAL) { -- ctor = is3DNode ? RadialFilled3D : RadialFilled; -+ ctor = is3DNode ? RadialFilled3D : (isMultiMaterial ? RadialFilledMulti : RadialFilled); - } else { -- ctor = is3DNode ? BarFilled3D : BarFilled; -+ ctor = is3DNode ? BarFilled3D : (isMultiMaterial ? BarFilledMulti : BarFilled); - } - break; - case Type.MESH: -- ctor = is3DNode ? Mesh3D : Mesh; -+ ctor = is3DNode ? Mesh3D : (isMultiMaterial ? MeshMulti : Mesh); - break; - } - -@@ -55,6 +64,13 @@ let ctor = { - RadialFilled3D, - BarFilled3D, - Mesh3D, -+ -+ SimpleMulti, -+ SlicedMulti, -+ TiledMulti, -+ RadialFilledMulti, -+ BarFilledMulti, -+ MeshMulti, - }; - - Assembler.register(cc.Sprite, ctor); -diff --git a/engine/cocos2d/core/renderer/webgl/vertex-format.js b/engine/cocos2d/core/renderer/webgl/vertex-format.js -index 53e817a..4a93586 100644 ---- a/engine/cocos2d/core/renderer/webgl/vertex-format.js -+++ b/engine/cocos2d/core/renderer/webgl/vertex-format.js -@@ -41,6 +41,15 @@ var vfmtPosUvColor = new gfx.VertexFormat([ - vfmtPosUvColor.name = 'vfmtPosUvColor'; - gfx.VertexFormat.XY_UV_Color = vfmtPosUvColor; - -+var vfmtPosUvColorTexId = new gfx.VertexFormat([ -+ { name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 }, -+ { name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 }, -+ { name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true }, -+ { name: gfx.ATTR_TEX_ID, type: gfx.ATTR_TYPE_FLOAT32, num: 1 }, -+]); -+vfmtPosUvColorTexId.name = 'vfmtPosUvColorTexId'; -+gfx.VertexFormat.XY_UV_Color_TexId = vfmtPosUvColorTexId; -+ - var vfmtPosUvTwoColor = new gfx.VertexFormat([ - { name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 }, - { name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 }, -@@ -76,5 +85,6 @@ module.exports = { - vfmtPosUvTwoColor, - vfmtPosUv, - vfmtPosColor, -- vfmtPos --}; -\ No newline at end of file -+ vfmtPos, -+ vfmtPosUvColorTexId -+}; -diff --git a/engine/cocos2d/renderer/gfx/enums.js b/engine/cocos2d/renderer/gfx/enums.js -index 9ecc685..69770ac 100644 ---- a/engine/cocos2d/renderer/gfx/enums.js -+++ b/engine/cocos2d/renderer/gfx/enums.js -@@ -178,6 +178,7 @@ export const enums = { - ATTR_TEX_COORD6: 'a_texCoord6', - ATTR_TEX_COORD7: 'a_texCoord7', - ATTR_TEX_COORD8: 'a_texCoord8', -+ ATTR_TEX_ID: 'a_texId', - - - // vertex attribute type -@@ -360,4 +361,4 @@ export function glTextureFmt(fmt) { - } - - return result; --} -\ No newline at end of file -+} -diff --git a/engine/modules.json b/engine/modules.json -index 4c1da42..71b0b44 100644 ---- a/engine/modules.json -+++ b/engine/modules.json -@@ -164,7 +164,8 @@ - "name": "MotionStreak", - "entries": [ - "./cocos2d/core/components/CCMotionStreak.js", -- "./cocos2d/core/renderer/webgl/assemblers/motion-streak.js" -+ "./cocos2d/core/renderer/webgl/assemblers/motion-streak.js", -+ "./cocos2d/core/renderer/webgl/assemblers/motion-streak-multi.js" - ], - "dependencies": ["WebGL Renderer"] - }, --- -2.32.0 (Apple Git-132) - diff --git a/patches/v1.0.0/0006-.patch b/patches/v1.0.0/0006-.patch deleted file mode 100644 index 50605e19..00000000 --- a/patches/v1.0.0/0006-.patch +++ /dev/null @@ -1,1236 +0,0 @@ -From 1076ad9f8452a04c250a90701a5603d550742666 Mon Sep 17 00:00:00 2001 -From: SmallMain -Date: Tue, 21 Jun 2022 11:37:49 +0800 -Subject: [PATCH 06/16] =?UTF-8?q?=E6=96=B0=E7=9A=84=E5=8A=A8=E6=80=81?= - =?UTF-8?q?=E5=9B=BE=E9=9B=86=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/assets/CCSpriteFrame.js | 5 + - engine/cocos2d/core/components/CCLabel.js | 4 + - engine/cocos2d/core/components/CCRichText.js | 30 +- - engine/cocos2d/core/components/CCSprite.js | 4 + - engine/cocos2d/core/renderer/assembler.js | 3 + - .../renderer/utils/dynamic-atlas/atlas.js | 139 +--- - .../renderer/utils/dynamic-atlas/manager.js | 172 ++++- - .../utils/dynamic-atlas/reusable-atlas.ts | 593 ++++++++++++++++++ - .../cocos2d/core/renderer/utils/label/ttf.js | 28 + - 10 files changed, 810 insertions(+), 170 deletions(-) - create mode 100644 engine/cocos2d/core/renderer/utils/dynamic-atlas/reusable-atlas.ts - -diff --git a/engine/cocos2d/core/asset-manager/builtins.js b/engine/cocos2d/core/asset-manager/builtins.js -index f794369..ea87ebe 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; - cb(); - }); - }, -diff --git a/engine/cocos2d/core/assets/CCSpriteFrame.js b/engine/cocos2d/core/assets/CCSpriteFrame.js -index cfb95ae..37837bd 100644 ---- a/engine/cocos2d/core/assets/CCSpriteFrame.js -+++ b/engine/cocos2d/core/assets/CCSpriteFrame.js -@@ -824,6 +824,11 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{ - handle.result.push(this, '_textureSetter', textureUuid); - } - } -+ }, -+ -+ destroy() { -+ cc.dynamicAtlasManager && cc.dynamicAtlasManager.deleteSpriteFrame(this); -+ this._super(); - } - }); - -diff --git a/engine/cocos2d/core/components/CCLabel.js b/engine/cocos2d/core/components/CCLabel.js -index f2c372f..013968b 100644 ---- a/engine/cocos2d/core/components/CCLabel.js -+++ b/engine/cocos2d/core/components/CCLabel.js -@@ -583,6 +583,10 @@ let Label = cc.Class({ - type: RenderComponent.EnableType, - default: RenderComponent.EnableType.GLOBAL, - }, -+ allowDynamicAtlas: { -+ type: RenderComponent.EnableType, -+ default: RenderComponent.EnableType.GLOBAL, -+ }, - }, - - statics: { -diff --git a/engine/cocos2d/core/components/CCRichText.js b/engine/cocos2d/core/components/CCRichText.js -index ae1183e..160184a 100644 ---- a/engine/cocos2d/core/components/CCRichText.js -+++ b/engine/cocos2d/core/components/CCRichText.js -@@ -373,7 +373,31 @@ let RichText = cc.Class({ - } - } - } -- } -+ }, -+ -+ allowDynamicAtlas: { -+ type: RenderComponent.EnableType, -+ default: RenderComponent.EnableType.GLOBAL, -+ notify: function (oldValue) { -+ if (this.allowDynamicAtlas === oldValue) return; -+ for (let i = 0; i < this._labelSegments.length; i++) { -+ const labelComponent = this._labelSegments[i].getComponent(cc.Label); -+ if (labelComponent) { -+ labelComponent.allowDynamicAtlas = this.allowDynamicAtlas; -+ } -+ const spriteComponent = this._labelSegments[i].getComponent(cc.Sprite); -+ if (spriteComponent) { -+ spriteComponent.allowDynamicAtlas = this.allowDynamicAtlas; -+ } -+ } -+ for (let i = 0; i < this._labelSegmentsCache.length; i++) { -+ const labelComponent = this._labelSegmentsCache[i].getComponent(cc.Label); -+ if (labelComponent) { -+ labelComponent.allowDynamicAtlas = this.allowDynamicAtlas; -+ } -+ } -+ } -+ }, - }, - - statics: { -@@ -685,6 +709,8 @@ let RichText = cc.Class({ - let spriteComponent = spriteNode.addComponent(cc.Sprite); - - spriteComponent.autoSwitchMaterial = this.autoSwitchMaterial; -+ spriteComponent.allowDynamicAtlas = this.allowDynamicAtlas; -+ - switch (richTextElement.style.imageAlign) - { - case 'top': -@@ -978,6 +1004,8 @@ let RichText = cc.Class({ - labelComponent.cacheMode = this.cacheMode; - - labelComponent.autoSwitchMaterial = this.autoSwitchMaterial; -+ labelComponent.allowDynamicAtlas = this.allowDynamicAtlas; -+ - let isAsset = this.font instanceof cc.Font; - if (isAsset && !this._isSystemFontUsed) { - labelComponent.font = this.font; -diff --git a/engine/cocos2d/core/components/CCSprite.js b/engine/cocos2d/core/components/CCSprite.js -index f0cf757..806a50d 100644 ---- a/engine/cocos2d/core/components/CCSprite.js -+++ b/engine/cocos2d/core/components/CCSprite.js -@@ -389,6 +389,10 @@ var Sprite = cc.Class({ - type: RenderComponent.EnableType, - default: RenderComponent.EnableType.GLOBAL, - }, -+ allowDynamicAtlas: { -+ type: RenderComponent.EnableType, -+ default: RenderComponent.EnableType.GLOBAL, -+ }, - }, - - statics: { -diff --git a/engine/cocos2d/core/renderer/assembler.js b/engine/cocos2d/core/renderer/assembler.js -index a65088b..0174930 100644 ---- a/engine/cocos2d/core/renderer/assembler.js -+++ b/engine/cocos2d/core/renderer/assembler.js -@@ -27,12 +27,15 @@ export default class Assembler { - packDynamicAtlasAndCheckMaterial(comp, frame) { - if (CC_TEST) return false; - -+ const allowDynamicAtlas = comp.allowDynamicAtlas; -+ if ((cc.sp.allowDynamicAtlas && allowDynamicAtlas === 0) || allowDynamicAtlas === 1) { - if (!frame._original && dynamicAtlasManager && frame._texture.packable) { - let packedFrame = dynamicAtlasManager.insertSpriteFrame(frame); - if (packedFrame) { - frame._setDynamicAtlasFrame(packedFrame); - } - } -+ } - - const material = comp._materials[0]; - if (!material) return false; -diff --git a/engine/cocos2d/core/renderer/utils/dynamic-atlas/atlas.js b/engine/cocos2d/core/renderer/utils/dynamic-atlas/atlas.js -index e6b990a..e489846 100644 ---- a/engine/cocos2d/core/renderer/utils/dynamic-atlas/atlas.js -+++ b/engine/cocos2d/core/renderer/utils/dynamic-atlas/atlas.js -@@ -1,140 +1,5 @@ --const RenderTexture = require('../../../assets/CCRenderTexture'); -- --const space = 2; -- --function Atlas (width, height) { -- let texture = new RenderTexture(); -- texture.initWithSize(width, height); -- texture.update(); -- -- this._texture = texture; -- -- this._x = space; -- this._y = space; -- this._nexty = space; -- -- this._width = width; -- this._height = height; -- -- this._innerTextureInfos = {}; -- this._innerSpriteFrames = []; -- -- this._count = 0; -+// 保留备用 -+function Atlas(width, height) { - } - --Atlas.DEFAULT_HASH = (new RenderTexture())._getHash(); -- --cc.js.mixin(Atlas.prototype, { -- insertSpriteFrame (spriteFrame) { -- let rect = spriteFrame._rect, -- texture = spriteFrame._texture, -- info = this._innerTextureInfos[texture._id]; -- -- let sx = rect.x, sy = rect.y; -- -- if (info) { -- sx += info.x; -- sy += info.y; -- } -- else { -- let width = texture.width, height = texture.height; -- -- if ((this._x + width + space) > this._width) { -- this._x = space; -- this._y = this._nexty; -- } -- -- if ((this._y + height + space) > this._nexty) { -- this._nexty = this._y + height + space; -- } -- -- if (this._nexty > this._height) { -- return null; -- } -- -- // texture bleeding -- if (cc.dynamicAtlasManager.textureBleeding) { -- // Smaller frame is more likely to be affected by linear filter -- if (width <= 8 || height <= 8) { -- this._texture.drawTextureAt(texture, this._x-1, this._y-1); -- this._texture.drawTextureAt(texture, this._x-1, this._y+1); -- this._texture.drawTextureAt(texture, this._x+1, this._y-1); -- this._texture.drawTextureAt(texture, this._x+1, this._y+1); -- } -- -- this._texture.drawTextureAt(texture, this._x-1, this._y); -- this._texture.drawTextureAt(texture, this._x+1, this._y); -- this._texture.drawTextureAt(texture, this._x, this._y-1); -- this._texture.drawTextureAt(texture, this._x, this._y+1); -- } -- -- this._texture.drawTextureAt(texture, this._x, this._y); -- -- this._innerTextureInfos[texture._id] = { -- x: this._x, -- y: this._y, -- texture: texture -- }; -- -- this._count++; -- -- sx += this._x; -- sy += this._y; -- -- this._x += width + space; -- -- this._dirty = true; -- } -- -- let frame = { -- x: sx, -- y: sy, -- texture: this._texture -- } -- -- this._innerSpriteFrames.push(spriteFrame); -- -- return frame; -- }, -- -- update () { -- if (!this._dirty) return; -- this._texture.update(); -- this._dirty = false; -- }, -- -- deleteInnerTexture (texture) { -- if (texture && this._innerTextureInfos[texture._id]) { -- delete this._innerTextureInfos[texture._id]; -- this._count--; -- } -- }, -- -- isEmpty () { -- return this._count <= 0; -- }, -- -- reset () { -- this._x = space; -- this._y = space; -- this._nexty = space; -- -- let frames = this._innerSpriteFrames; -- for (let i = 0, l = frames.length; i < l; i++) { -- let frame = frames[i]; -- if (!frame.isValid) { -- continue; -- } -- frame._resetDynamicAtlasFrame(); -- } -- this._innerSpriteFrames.length = 0; -- this._innerTextureInfos = {}; -- }, -- -- destroy () { -- this.reset(); -- this._texture.destroy(); -- } --}); -- - module.exports = Atlas; -diff --git a/engine/cocos2d/core/renderer/utils/dynamic-atlas/manager.js b/engine/cocos2d/core/renderer/utils/dynamic-atlas/manager.js -index d377566..8cd4b35 100644 ---- a/engine/cocos2d/core/renderer/utils/dynamic-atlas/manager.js -+++ b/engine/cocos2d/core/renderer/utils/dynamic-atlas/manager.js -@@ -1,12 +1,15 @@ --const Atlas = require('./atlas'); -+// const Atlas = require('./atlas'); -+import { Atlas, Rect } from './reusable-atlas'; - - let _atlases = []; - let _atlasIndex = -1; - --let _maxAtlasCount = 5; -+let _maxAtlasCount = -1; - let _textureSize = 2048; - let _maxFrameSize = 512; - let _textureBleeding = true; -+let _autoMultiBatch = true; -+let _autoResetBeforeSceneLoad = true; - - let _debugNode = null; - -@@ -15,12 +18,15 @@ function newAtlas () { - if (!atlas) { - atlas = new Atlas(_textureSize, _textureSize); - _atlases.push(atlas); -+ if (dynamicAtlasManager.autoMultiBatch) cc.sp.multiBatcher.requsetMaterial(atlas._texture); - } - return atlas; - } - --function beforeSceneLoad () { -- dynamicAtlasManager.reset(); -+function beforeSceneLoad() { -+ if (_autoResetBeforeSceneLoad) { -+ dynamicAtlasManager.reset(); -+ } - } - - let _enabled = false; -@@ -32,6 +38,7 @@ let _enabled = false; - */ - let dynamicAtlasManager = { - Atlas: Atlas, -+ Rect: Rect, - - /** - * !#en Enable or disable the dynamic atlas, see [Dynamic Atlas](https://docs.cocos.com/creator/manual/en/advanced-topics/dynamic-atlas.html) for details. -@@ -39,10 +46,10 @@ let dynamicAtlasManager = { - * @property enabled - * @type {Boolean} - */ -- get enabled () { -+ get enabled() { - return _enabled; - }, -- set enabled (value) { -+ set enabled(value) { - if (_enabled === value) return; - - if (value) { -@@ -62,10 +69,10 @@ let dynamicAtlasManager = { - * @property maxAtlasCount - * @type {Number} - */ -- get maxAtlasCount () { -+ get maxAtlasCount() { - return _maxAtlasCount; - }, -- set maxAtlasCount (value) { -+ set maxAtlasCount(value) { - _maxAtlasCount = value; - }, - -@@ -75,7 +82,7 @@ let dynamicAtlasManager = { - * @property atlasCount - * @type {Number} - */ -- get atlasCount () { -+ get atlasCount() { - return _atlases.length; - }, - -@@ -85,11 +92,11 @@ let dynamicAtlasManager = { - * @property textureBleeding - * @type {Boolean} - */ -- get textureBleeding () { -+ get textureBleeding() { - return _textureBleeding; - }, - -- set textureBleeding (enable) { -+ set textureBleeding(enable) { - _textureBleeding = enable; - }, - -@@ -99,10 +106,10 @@ let dynamicAtlasManager = { - * @property textureSize - * @type {Number} - */ -- get textureSize () { -+ get textureSize() { - return _textureSize; - }, -- set textureSize (value) { -+ set textureSize(value) { - _textureSize = value; - }, - -@@ -112,13 +119,65 @@ let dynamicAtlasManager = { - * @property maxFrameSize - * @type {Number} - */ -- get maxFrameSize () { -+ get maxFrameSize() { - return _maxFrameSize; - }, -- set maxFrameSize (value) { -+ set maxFrameSize(value) { - _maxFrameSize = value; - }, - -+ /** -+ * !#en Is enable autoMultiBatch. -+ * !#zh 是否开启自动多纹理合批 -+ * @property autoMultiBatch -+ * @type {Boolean} -+ */ -+ get autoMultiBatch() { -+ return _autoMultiBatch; -+ }, -+ -+ set autoMultiBatch(enable) { -+ if (_autoMultiBatch === enable) return; -+ -+ if (enable) { -+ for (let i = 0, l = _atlases.length; i < l; i++) { -+ cc.sp.multiBatcher.requsetMaterial(_atlases[i]._texture); -+ } -+ } -+ -+ _autoMultiBatch = enable; -+ }, -+ -+ /** -+ * !#en Is enable autoResetBeforeSceneLoad. -+ * !#zh 是否在场景切换时清空所有图集 -+ * @property autoResetBeforeSceneLoad -+ * @type {Boolean} -+ */ -+ get autoResetBeforeSceneLoad() { -+ return _autoResetBeforeSceneLoad; -+ }, -+ -+ set autoResetBeforeSceneLoad(enable) { -+ if (_autoResetBeforeSceneLoad === enable) return; -+ _autoResetBeforeSceneLoad = enable; -+ }, -+ -+ /** -+ * !#en atlases -+ * !#zh 图集数组 -+ * @property atlases -+ * @type {Atlas} -+ */ -+ get atlases() { -+ return _atlases; -+ }, -+ -+ /** -+ * 已用空间集合 -+ */ -+ rects: Object.create(null), -+ - /** - * !#en The minimum size of the picture that can be added to the atlas. - * !#zh 可以添加进图集的图片的最小尺寸。 -@@ -133,26 +192,77 @@ let dynamicAtlasManager = { - * @method insertSpriteFrame - * @param {SpriteFrame} spriteFrame - */ -- insertSpriteFrame (spriteFrame) { -+ insertSpriteFrame(spriteFrame) { - if (CC_EDITOR) return null; -- if (!_enabled || _atlasIndex === _maxAtlasCount || -- !spriteFrame || spriteFrame._original) return null; -+ if (!_enabled || !spriteFrame || spriteFrame._original) return null; - -- if (!spriteFrame._texture.packable) return null; -+ let atlas, frame; - -- let atlas = _atlases[_atlasIndex]; -- if (!atlas) { -- atlas = newAtlas(); -+ // 是否贴图已经在图集中 -+ let rect = spriteFrame._rect, -+ texture = spriteFrame._texture, -+ info = this.rects[texture._uuid]; -+ -+ let sx = rect.x, sy = rect.y; -+ -+ if (info) { -+ sx += info.x; -+ sy += info.y; -+ -+ info.spriteFrames.push(spriteFrame); -+ -+ frame = { -+ x: sx, -+ y: sy, -+ texture: info.atlas._texture, -+ }; -+ -+ return frame; - } - -- let frame = atlas.insertSpriteFrame(spriteFrame); -- if (!frame && _atlasIndex !== _maxAtlasCount) { -+ // 尝试加入已有图集 -+ for (let i = 0; i <= _atlasIndex; i++) { -+ atlas = _atlases[i]; -+ frame = atlas.insertSpriteFrame(spriteFrame); -+ if (frame) { -+ return frame; -+ } -+ } -+ -+ // 创建新图集尝试加入 -+ if (_atlasIndex + 1 < _maxAtlasCount) { - atlas = newAtlas(); - return atlas.insertSpriteFrame(spriteFrame); - } -+ - return frame; - }, - -+ /** -+ * !#en Delete a sprite frame from the dynamic atlas. -+ * !#zh 使精灵帧取消使用动态图集 -+ * @method deleteSpriteFrame -+ * @param {SpriteFrame} spriteFrame -+ */ -+ deleteSpriteFrame(spriteFrame) { -+ if (spriteFrame && !CC_TEST) { -+ if (spriteFrame._original) { -+ this.deleteAtlasSpriteFrame(spriteFrame); -+ spriteFrame._resetDynamicAtlasFrame(); -+ } -+ } -+ }, -+ -+ /** -+ * !#en Delete a texture from the dynamic atlas. -+ * !#zh 从动态图集删除该贴图,使用该贴图的精灵帧会被还原 -+ * @method deleteTexture -+ * @param {Texture2D} texture -+ */ -+ deleteTexture(texture) { -+ this.deleteAtlasTexture(texture); -+ }, -+ - /** - * !#en Resets all dynamic atlas, and the existing ones will be destroyed. - * !#zh 重置所有动态图集,已有的动态图集会被销毁。 -@@ -170,18 +280,18 @@ let dynamicAtlasManager = { - if (!spriteFrame._original) return; - - let texture = spriteFrame._original._texture; -- this.deleteAtlasTexture(texture); -+ for (let i = _atlases.length - 1; i >= 0; i--) { -+ if (_atlases[i].deleteSpriteFrame(texture, spriteFrame)) { -+ return; -+ } -+ } - }, - - deleteAtlasTexture (texture) { - if (texture) { - for (let i = _atlases.length - 1; i >= 0; i--) { -- _atlases[i].deleteInnerTexture(texture); -- -- if (_atlases[i].isEmpty()) { -- _atlases[i].destroy(); -- _atlases.splice(i, 1); -- _atlasIndex--; -+ if (_atlases[i].deleteInnerTexture(texture, true)) { -+ return; - } - } - } -diff --git a/engine/cocos2d/core/renderer/utils/dynamic-atlas/reusable-atlas.ts b/engine/cocos2d/core/renderer/utils/dynamic-atlas/reusable-atlas.ts -new file mode 100644 -index 0000000..9ba1adc ---- /dev/null -+++ b/engine/cocos2d/core/renderer/utils/dynamic-atlas/reusable-atlas.ts -@@ -0,0 +1,593 @@ -+// @ts-expect-error -+const RenderTexture = require('../../../assets/CCRenderTexture'); -+ -+ -+/** -+ * 矩形 -+ */ -+export class Rect { -+ -+ /** -+ * 对象池 -+ */ -+ static pool: Rect[] = []; -+ -+ /** -+ * 对象池指针 -+ */ -+ static pointer: number = 0; -+ -+ -+ /** -+ * 复用 -+ */ -+ static reuse(atlas: Atlas, width: number, height: number, x: number, y: number) { -+ if (this.pointer === 0) { -+ for (let i = 0; i < 128; i++) { -+ Rect.pool[i] = new Rect(atlas, 0, 0, 0, 0); -+ } -+ this.pointer += 128; -+ } -+ -+ this.pointer--; -+ const rect = this.pool[this.pointer]; -+ -+ rect.atlas = atlas; -+ rect.width = width; -+ rect.height = height; -+ rect.x = x; -+ rect.y = y; -+ -+ return rect; -+ } -+ -+ -+ /** -+ * 回收 -+ */ -+ static recycle(rect: Rect) { -+ rect.atlas = undefined!; -+ rect.uuid = ""; -+ rect.spriteFrames.length = 0; -+ rect.parentRect = undefined; -+ rect.subRectA = undefined; -+ rect.subRectB = undefined; -+ rect.subRectC = undefined; -+ -+ rect.cacheIndex = -1; -+ -+ this.pool[this.pointer] = rect; -+ this.pointer++; -+ } -+ -+ -+ /** -+ * 所属 Atlas -+ */ -+ atlas: Atlas; -+ -+ /** -+ * 宽度 -+ */ -+ width: number = 0; -+ -+ /** -+ * 高度 -+ */ -+ height: number = 0; -+ -+ /** -+ * 横坐标 -+ */ -+ x: number = 0; -+ -+ /** -+ * 纵坐标 -+ */ -+ y: number = 0; -+ -+ /** -+ * 在 freeRects 中的下标 -+ */ -+ cacheIndex: number = -1; -+ -+ /** -+ * cc.Texture2D UUID -+ */ -+ uuid: string = ''; -+ -+ /** -+ * 使用该贴图的精灵帧数组 -+ */ -+ spriteFrames: any[] = []; -+ -+ /** -+ * 父矩形 -+ */ -+ parentRect: Rect | undefined; -+ -+ /** -+ * 子矩形之一 -+ */ -+ subRectA: Rect | undefined; -+ -+ /** -+ * 子矩形之一 -+ */ -+ subRectB: Rect | undefined; -+ -+ /** -+ * 子矩形之一 -+ */ -+ subRectC: Rect | undefined; -+ -+ /** -+ * 子矩形或自身计数 -+ */ -+ used: number = 0; -+ -+ /** -+ * 像素数 -+ */ -+ get sizes() { -+ return this.width * this.height; -+ } -+ -+ -+ constructor(atlas: Atlas, width: number, height: number, x: number, y: number) { -+ this.atlas = atlas; -+ this.width = width; -+ this.height = height; -+ this.x = x; -+ this.y = y; -+ } -+ -+} -+ -+ -+/** -+ * 动态图集 -+ * -+ * 装箱算法:类似断头台装箱算法 -+ * 合并算法:树形回退模式 -+ */ -+export class Atlas { -+ -+ /** -+ * 当自由空间的某边长度不足该值则直接忽略该空间 -+ */ -+ static ignoreRectSize: number = 10; -+ -+ /** -+ * 默认 Atlas -+ */ -+ static DEFAULT_HASH = (new RenderTexture())._getHash(); -+ -+ /** -+ * 宽度 -+ */ -+ width: number = 0; -+ -+ /** -+ * 高度 -+ */ -+ height: number = 0; -+ -+ /** -+ * 间距 -+ */ -+ padding: number = 0; -+ -+ /** -+ * 边距 -+ */ -+ border: number = 0; -+ -+ /** -+ * 根矩形 -+ */ -+ rootRect: Rect; -+ -+ /** -+ * 自由空间 -+ */ -+ freeRects: Rect[] = []; -+ -+ /** -+ * 已使用数量 -+ */ -+ _count = 0; -+ -+ /** -+ * cc.RenderTexture -+ */ -+ _texture: any; -+ -+ /** -+ * texture update dirty -+ */ -+ _dirty: boolean = false; -+ -+ -+ constructor(width: number, height: number, padding: number = 2, border: number = 2) { -+ const texture = new RenderTexture(); -+ texture.initWithSize(width, height); -+ texture.update(); -+ this._texture = texture; -+ -+ this.width = width; -+ this.height = height; -+ this.padding = padding; -+ this.border = border; -+ -+ this.rootRect = Rect.reuse( -+ this, -+ this.width + this.padding - this.border * 2, -+ this.height + this.padding - this.border * 2, -+ this.border, -+ this.border, -+ ); -+ this.pushFreeRect(this.rootRect); -+ } -+ -+ -+ /** -+ * push to free rects -+ */ -+ protected pushFreeRect(rect: Rect) { -+ const i = this.freeRects.push(rect) - 1; -+ rect.cacheIndex = i; -+ } -+ -+ -+ /** -+ * faster remove from free rects -+ */ -+ protected removeFreeRect(index: number) { -+ const temp = this.freeRects[index]; -+ const temp2 = this.freeRects[this.freeRects.length - 1]; -+ temp2.cacheIndex = index; -+ temp.cacheIndex = -1; -+ this.freeRects[index] = temp2; -+ this.freeRects.pop(); -+ } -+ -+ -+ /** -+ * change member from free rects -+ */ -+ protected replaceFreeRect(index: number, rect: Rect) { -+ this.freeRects[index].cacheIndex = -1; -+ rect.cacheIndex = index; -+ this.freeRects[index] = rect; -+ } -+ -+ -+ /** -+ * 插入 SpriteFrame -+ */ -+ insertSpriteFrame(spriteFrame: any) { -+ let rect = spriteFrame._rect, -+ texture = spriteFrame._texture; -+ -+ let sx = rect.x, sy = rect.y; -+ let width = texture.width, height = texture.height; -+ -+ const result = this.insert(texture); -+ -+ if (!result) { -+ return null; -+ } -+ -+ // texture bleeding -+ if (cc.dynamicAtlasManager.textureBleeding) { -+ // Smaller frame is more likely to be affected by linear filter -+ if (width <= 8 || height <= 8) { -+ this._texture.drawTextureAt(texture, result.x - 1, result.y - 1); -+ this._texture.drawTextureAt(texture, result.x - 1, result.y + 1); -+ this._texture.drawTextureAt(texture, result.x + 1, result.y - 1); -+ this._texture.drawTextureAt(texture, result.x + 1, result.y + 1); -+ } -+ -+ this._texture.drawTextureAt(texture, result.x - 1, result.y); -+ this._texture.drawTextureAt(texture, result.x + 1, result.y); -+ this._texture.drawTextureAt(texture, result.x, result.y - 1); -+ this._texture.drawTextureAt(texture, result.x, result.y + 1); -+ } -+ -+ this._texture.drawTextureAt(texture, result.x, result.y); -+ -+ this._count++; -+ -+ sx += result.x; -+ sy += result.y; -+ -+ result.spriteFrames.push(spriteFrame); -+ -+ this._dirty = true; -+ -+ let frame = { -+ x: sx, -+ y: sy, -+ texture: this._texture, -+ }; -+ -+ return frame; -+ } -+ -+ -+ /** -+ * 插入子函数 -+ */ -+ insert(texture: any) { -+ const width = texture.width + this.padding, height = texture.height + this.padding; -+ let score = Number.MAX_VALUE; -+ let areaFit = 0; -+ let original: Rect | undefined = undefined; -+ let originalIndex = 0; -+ -+ // 查找足够容纳的空区域 -+ for (let i = 0; i < this.freeRects.length; i++) { -+ const rect = this.freeRects[i]; -+ if (rect.width >= width && rect.height >= height) { -+ areaFit = rect.sizes - width * height; -+ if (areaFit < score) { -+ original = rect; -+ originalIndex = i; -+ score = areaFit; -+ } -+ } -+ } -+ -+ // 切割空区域 -+ if (original) { -+ if (original.width === width && original.height === height) { -+ original.uuid = texture._uuid; -+ original.used++; -+ if (original.parentRect) original.parentRect.used++; -+ cc.dynamicAtlasManager.rects[texture._uuid] = original; -+ this.removeFreeRect(originalIndex); -+ return original; -+ } -+ -+ const best = Rect.reuse(this, width, height, original.x, original.y); -+ let tmp: Rect; -+ if (best.y + best.height < original.y + original.height) { -+ tmp = Rect.reuse( -+ this, -+ original.width, -+ original.y + original.height - (best.y + best.height), -+ original.x, -+ best.y + best.height, -+ ); -+ -+ tmp.parentRect = original; -+ original.subRectB = tmp; -+ -+ if (tmp.width > Atlas.ignoreRectSize && tmp.height > Atlas.ignoreRectSize) { -+ // 替换旧区域 -+ this.replaceFreeRect(originalIndex, tmp); -+ originalIndex = -1; -+ } -+ } -+ -+ if (best.x + best.width < original.x + original.width) { -+ tmp = Rect.reuse( -+ this, -+ original.x + original.width - (best.x + best.width), -+ original.height - (original.y + original.height - (best.y + best.height)), -+ best.x + best.width, -+ original.y, -+ ); -+ -+ tmp.parentRect = original; -+ original.subRectC = tmp; -+ -+ if (tmp.width > Atlas.ignoreRectSize && tmp.height > Atlas.ignoreRectSize) { -+ if (originalIndex !== -1) { -+ // 替换旧区域 -+ this.replaceFreeRect(originalIndex, tmp); -+ originalIndex = -1; -+ } else { -+ this.pushFreeRect(tmp); -+ } -+ } -+ } -+ -+ if (originalIndex !== -1) { -+ this.removeFreeRect(originalIndex); -+ } -+ -+ best.parentRect = original; -+ original.subRectA = best; -+ best.used++; -+ original.used++; -+ if (original.used === 1 && original.parentRect) original.parentRect.used++; -+ best.uuid = texture._uuid; -+ cc.dynamicAtlasManager.rects[texture._uuid] = best; -+ return best; -+ } else { -+ return undefined; -+ } -+ } -+ -+ -+ /** -+ * update texture -+ */ -+ update() { -+ if (!this._dirty) return; -+ this._texture.update(); -+ this._dirty = false; -+ } -+ -+ -+ /** -+ * 删除精灵帧 -+ */ -+ deleteSpriteFrame(texture: any, frame: any) { -+ if (texture) { -+ const rect: Rect | undefined = cc.dynamicAtlasManager.rects[texture._uuid]; -+ if (rect) { -+ const index = rect.spriteFrames.indexOf(frame); -+ if (index !== -1) { -+ rect.spriteFrames.splice(index, 1); -+ -+ // 判断如果没有引用则删除 Texture -+ if (rect.spriteFrames.length === 0) { -+ rect.atlas.deleteInnerRect(rect); -+ } -+ } else { -+ cc.warn('[Dynamic Atlas] can\'t find spriteFrame in Rect.'); -+ } -+ -+ return true; -+ } -+ } -+ -+ return false; -+ } -+ -+ -+ /** -+ * 删除子矩形 -+ */ -+ deleteInnerRect(rect: Rect) { -+ delete cc.dynamicAtlasManager.rects[rect.uuid]; -+ rect.uuid = ""; -+ this._count--; -+ -+ // 还原 SpriteFrame -+ for (const spriteFrame of rect.spriteFrames) { -+ if (spriteFrame.isValid) { -+ spriteFrame._resetDynamicAtlasFrame(); -+ } -+ } -+ rect.spriteFrames.length = 0; -+ -+ this.tryMergeRecycle(rect); -+ } -+ -+ -+ /** -+ * 删除贴图 -+ */ -+ deleteInnerTexture(texture: any) { -+ if (texture) { -+ const rect: Rect | undefined = cc.dynamicAtlasManager.rects[texture._uuid]; -+ if (rect) { -+ rect.atlas.deleteInnerRect(rect); -+ return true; -+ } -+ } -+ return false; -+ } -+ -+ -+ /** -+ * 尝试合并和回收 -+ */ -+ protected tryMergeRecycle(rect: Rect) { -+ let old: Rect | undefined = undefined; -+ let parent: Rect | undefined = rect; -+ while (parent) { -+ parent.used--; -+ if (parent.used === 0) { -+ // 回收所有子矩形 -+ if (parent.subRectA) { -+ // 可能是 ignoreRect -+ const i = parent.subRectA.cacheIndex; -+ if (i !== -1) { -+ this.removeFreeRect(i); -+ } -+ Rect.recycle(parent.subRectA); -+ parent.subRectA = undefined; -+ } -+ if (parent.subRectB) { -+ const i = parent.subRectB.cacheIndex; -+ if (i !== -1) { -+ this.removeFreeRect(i); -+ } -+ Rect.recycle(parent.subRectB); -+ parent.subRectB = undefined; -+ } -+ if (parent.subRectC) { -+ const i = parent.subRectC.cacheIndex; -+ if (i !== -1) { -+ this.removeFreeRect(i); -+ } -+ Rect.recycle(parent.subRectC); -+ parent.subRectC = undefined; -+ } -+ old = parent; -+ parent = parent.parentRect; -+ } else { -+ if (old) { -+ if (old.width > Atlas.ignoreRectSize && old.height > Atlas.ignoreRectSize) { -+ this.pushFreeRect(old); -+ } -+ } -+ old = parent; -+ parent = undefined; -+ } -+ } -+ -+ if (old === this.rootRect && old.used === 0) { -+ this.pushFreeRect(old); -+ } -+ } -+ -+ -+ /** -+ * 是否未使用 -+ */ -+ isEmpty() { -+ return this._count <= 0; -+ } -+ -+ -+ /** -+ * 清空 -+ */ -+ reset() { -+ const rects = cc.dynamicAtlasManager.rects; -+ for (const key in rects) { -+ const rect: Rect = rects[key]; -+ if (rect.atlas === this) { -+ delete rects[key]; -+ for (const spriteFrame of rect.spriteFrames) { -+ if (spriteFrame.isValid) { -+ spriteFrame._resetDynamicAtlasFrame(); -+ } -+ } -+ Rect.recycle(rect); -+ } -+ } -+ -+ for (const rect of this.freeRects) { -+ Rect.recycle(rect); -+ } -+ -+ this.freeRects.length = 0; -+ this._count = 0; -+ -+ this.rootRect = Rect.reuse( -+ this, -+ this.width + this.padding - this.border * 2, -+ this.height + this.padding - this.border * 2, -+ this.border, -+ this.border, -+ ); -+ this.pushFreeRect(this.rootRect) -+ } -+ -+ -+ /** -+ * 销毁 -+ */ -+ destroy() { -+ this.reset(); -+ this._texture.destroy(); -+ } -+ -+} -diff --git a/engine/cocos2d/core/renderer/utils/label/ttf.js b/engine/cocos2d/core/renderer/utils/label/ttf.js -index 9d85e3f..49d90fa 100644 ---- a/engine/cocos2d/core/renderer/utils/label/ttf.js -+++ b/engine/cocos2d/core/renderer/utils/label/ttf.js -@@ -353,6 +353,34 @@ export default class TTFAssembler extends Assembler2D { - return this.packDynamicAtlasAndCheckMaterial(comp, frame); - } - -+ packDynamicAtlasAndCheckMaterial(comp, frame) { -+ const allowDynamicAtlas = comp.allowDynamicAtlas; -+ if ((cc.sp.allowDynamicAtlas && allowDynamicAtlas === 0) || allowDynamicAtlas === 1) { -+ frame._texture._uuid = _fontDesc -+ + _overflow -+ + (_premultiply ? 'P' : 'NP') -+ + (_enableUnderline ? 'UL' : 'NUL') -+ + _string; -+ -+ if (_outlineComp) { -+ frame._texture._uuid += _outlineComp.color.toHEX() -+ + ',' -+ + _outlineComp.width -+ + ','; -+ } -+ -+ if (_shadowComp) { -+ frame._texture._uuid += _shadowComp.color.toHEX() -+ + _shadowComp.offset.x -+ + ',' -+ + _shadowComp.offset.y -+ + ',' -+ + _shadowComp.blur; -+ } -+ } -+ return super.packDynamicAtlasAndCheckMaterial(comp, frame); -+ } -+ - _updateLabelDimensions () { - _canvasSize.width = Math.min(_canvasSize.width, MAX_SIZE); - _canvasSize.height = Math.min(_canvasSize.height, MAX_SIZE); --- -2.32.0 (Apple Git-132) - diff --git a/patches/v1.0.0/0007-RichText.patch b/patches/v1.0.0/0007-RichText.patch deleted file mode 100644 index 8bf7a1da..00000000 --- a/patches/v1.0.0/0007-RichText.patch +++ /dev/null @@ -1,103 +0,0 @@ -From a5b45a75b5507abc8c7a7c48bea9587fd7ef4f00 Mon Sep 17 00:00:00 2001 -From: SmallMain -Date: Tue, 21 Jun 2022 11:42:39 +0800 -Subject: [PATCH 07/16] =?UTF-8?q?RichText=20=E6=94=AF=E6=8C=81=E8=87=AA?= - =?UTF-8?q?=E5=AE=9A=E4=B9=89=E6=9D=90=E8=B4=A8?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - ---- - engine/cocos2d/core/components/CCRichText.js | 62 ++++++++++++++++++++ - 1 file changed, 62 insertions(+) - -diff --git a/engine/cocos2d/core/components/CCRichText.js b/engine/cocos2d/core/components/CCRichText.js -index 160184a..cc13266 100644 ---- a/engine/cocos2d/core/components/CCRichText.js -+++ b/engine/cocos2d/core/components/CCRichText.js -@@ -351,6 +351,46 @@ let RichText = cc.Class({ - } - }, - -+ /** -+ * 自定义内部使用的材质 -+ */ -+ customMaterial: { -+ default: null, -+ type: cc.Material, -+ notify: function (oldValue) { -+ if (this.customMaterial === oldValue) return; -+ const material = this.customMaterial == null ? this._getDefaultMaterial() : this.customMaterial; -+ for (let i = 0; i < this._labelSegments.length; i++) { -+ const labelComponent = this._labelSegments[i].getComponent(cc.Label); -+ if (labelComponent) { -+ if (labelComponent._materials.length === 0) { -+ labelComponent._materials[0] = MaterialVariant.create(material, labelComponent); -+ } else { -+ labelComponent.setMaterial(0, material); -+ } -+ } -+ const spriteComponent = this._labelSegments[i].getComponent(cc.Sprite); -+ if (spriteComponent) { -+ if (spriteComponent._materials.length === 0) { -+ spriteComponent._materials[0] = MaterialVariant.create(material, spriteComponent); -+ } else { -+ spriteComponent.setMaterial(0, material); -+ } -+ } -+ } -+ for (let i = 0; i < this._labelSegmentsCache.length; i++) { -+ const labelComponent = this._labelSegmentsCache[i].getComponent(cc.Label); -+ if (labelComponent) { -+ if (labelComponent._materials.length === 0) { -+ labelComponent._materials[0] = MaterialVariant.create(material, labelComponent); -+ } else { -+ labelComponent.setMaterial(0, material); -+ } -+ } -+ } -+ } -+ }, -+ - autoSwitchMaterial: { - type: RenderComponent.EnableType, - default: RenderComponent.EnableType.GLOBAL, -@@ -711,6 +751,17 @@ let RichText = cc.Class({ - spriteComponent.autoSwitchMaterial = this.autoSwitchMaterial; - spriteComponent.allowDynamicAtlas = this.allowDynamicAtlas; - -+ // 更新材质 -+ if (this.customMaterial) { -+ if (spriteComponent._materials.length === 0) { -+ spriteComponent._materials[0] = MaterialVariant.create(this.customMaterial, spriteComponent); -+ } else { -+ if (spriteComponent._materials[0].material !== this.customMaterial) { -+ spriteComponent.setMaterial(0, this.customMaterial); -+ } -+ } -+ } -+ - switch (richTextElement.style.imageAlign) - { - case 'top': -@@ -1006,6 +1057,17 @@ let RichText = cc.Class({ - labelComponent.autoSwitchMaterial = this.autoSwitchMaterial; - labelComponent.allowDynamicAtlas = this.allowDynamicAtlas; - -+ // 更新材质 -+ if (this.customMaterial) { -+ if (labelComponent._materials.length === 0) { -+ labelComponent._materials[0] = MaterialVariant.create(this.customMaterial, labelComponent); -+ } else { -+ if (labelComponent._materials[0].material !== this.customMaterial) { -+ labelComponent.setMaterial(0, this.customMaterial); -+ } -+ } -+ } -+ - let isAsset = this.font instanceof cc.Font; - if (isAsset && !this._isSystemFontUsed) { - labelComponent.font = this.font; --- -2.32.0 (Apple Git-132) - diff --git a/patches/v1.0.0/0008-DPI.patch b/patches/v1.0.0/0008-DPI.patch deleted file mode 100644 index cdeccc2d..00000000 --- a/patches/v1.0.0/0008-DPI.patch +++ /dev/null @@ -1,275 +0,0 @@ -From f73ec2f9660d3bdf6bc809bccf42c1ebbb132778 Mon Sep 17 00:00:00 2001 -From: SmallMain -Date: Tue, 21 Jun 2022 11:45:33 +0800 -Subject: [PATCH 08/16] =?UTF-8?q?=E6=94=AF=E6=8C=81=E9=AB=98=20DPI=20?= - =?UTF-8?q?=E6=B8=B2=E6=9F=93?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - ---- - engine/cocos2d/core/components/CCLabel.js | 7 +++ - engine/cocos2d/core/components/CCRichText.js | 21 +++++++++ - .../core/renderer/utils/label/bmfont.js | 25 ++++++++++- - .../cocos2d/core/renderer/utils/label/ttf.js | 43 +++++++++++++++---- - .../webgl/assemblers/label/2d/bmfont.js | 5 +++ - .../renderer/webgl/assemblers/label/2d/ttf.js | 7 +-- - 6 files changed, 96 insertions(+), 12 deletions(-) - -diff --git a/engine/cocos2d/core/components/CCLabel.js b/engine/cocos2d/core/components/CCLabel.js -index 013968b..d5116cc 100644 ---- a/engine/cocos2d/core/components/CCLabel.js -+++ b/engine/cocos2d/core/components/CCLabel.js -@@ -587,6 +587,13 @@ let Label = cc.Class({ - type: RenderComponent.EnableType, - default: RenderComponent.EnableType.GLOBAL, - }, -+ enableRetina: { -+ type: RenderComponent.EnableType, -+ default: RenderComponent.EnableType.GLOBAL, -+ notify(oldValue) { -+ this.setVertsDirty(); -+ } -+ }, - }, - - statics: { -diff --git a/engine/cocos2d/core/components/CCRichText.js b/engine/cocos2d/core/components/CCRichText.js -index cc13266..7e0c254 100644 ---- a/engine/cocos2d/core/components/CCRichText.js -+++ b/engine/cocos2d/core/components/CCRichText.js -@@ -438,6 +438,26 @@ let RichText = cc.Class({ - } - } - }, -+ -+ enableRetina: { -+ type: RenderComponent.EnableType, -+ default: RenderComponent.EnableType.GLOBAL, -+ notify: function (oldValue) { -+ if (this.enableRetina === oldValue) return; -+ for (let i = 0; i < this._labelSegments.length; i++) { -+ const labelComponent = this._labelSegments[i].getComponent(cc.Label); -+ if (labelComponent) { -+ labelComponent.enableRetina = this.enableRetina; -+ } -+ } -+ for (let i = 0; i < this._labelSegmentsCache.length; i++) { -+ const labelComponent = this._labelSegmentsCache[i].getComponent(cc.Label); -+ if (labelComponent) { -+ labelComponent.enableRetina = this.enableRetina; -+ } -+ } -+ } -+ }, - }, - - statics: { -@@ -1056,6 +1076,7 @@ let RichText = cc.Class({ - - labelComponent.autoSwitchMaterial = this.autoSwitchMaterial; - labelComponent.allowDynamicAtlas = this.allowDynamicAtlas; -+ labelComponent.enableRetina = this.enableRetina; - - // 更新材质 - if (this.customMaterial) { -diff --git a/engine/cocos2d/core/renderer/utils/label/bmfont.js b/engine/cocos2d/core/renderer/utils/label/bmfont.js -index 57951a5..9568825 100644 ---- a/engine/cocos2d/core/renderer/utils/label/bmfont.js -+++ b/engine/cocos2d/core/renderer/utils/label/bmfont.js -@@ -75,6 +75,8 @@ let _isWrapText = false; - let _labelWidth = 0; - let _labelHeight = 0; - let _maxLineWidth = 0; -+let _isRetina = false; -+let _retinaScale = 1; - - export default class BmfontAssembler extends Assembler2D { - updateRenderData (comp) { -@@ -110,6 +112,12 @@ export default class BmfontAssembler extends Assembler2D { - this._updateContent(); - this.updateWorldVerts(comp); - -+ if (_isRetina) { -+ _contentSize.width /= _retinaScale; -+ _contentSize.height /= _retinaScale; -+ _fontSize /= _retinaScale; -+ } -+ - _comp._actualFontSize = _fontSize; - _comp.node.setContentSize(_contentSize); - -@@ -137,8 +145,14 @@ export default class BmfontAssembler extends Assembler2D { - shareLabelInfo.margin = 0; - } - -+ getTTFTextureSizeScale() { -+ return _isRetina ? _retinaScale : 1; -+ } -+ - _updateProperties (comp) { - _string = comp.string.toString(); -+ _isRetina = !(comp.font instanceof cc.BitmapFont) && (cc.sp.enableLabelRetina && comp.enableRetina === 0) || comp.enableRetina === 1; -+ _retinaScale = cc.sp.labelRetinaScale; - _fontSize = comp.fontSize; - _originFontSize = _fntConfig ? _fntConfig.fontSize : comp.fontSize; - _hAlign = comp.horizontalAlign; -@@ -150,6 +164,15 @@ export default class BmfontAssembler extends Assembler2D { - _contentSize.width = comp.node.width; - _contentSize.height = comp.node.height; - -+ if (_isRetina) { -+ _fontSize *= _retinaScale; -+ if (!_fntConfig) _originFontSize *= _retinaScale; -+ _contentSize.width *= _retinaScale; -+ _contentSize.height *= _retinaScale; -+ _lineHeight *= _retinaScale; -+ shareLabelInfo.margin *= _retinaScale; -+ } -+ - // should wrap text - if (_overflow === Overflow.NONE) { - _isWrapText = false; -@@ -706,4 +729,4 @@ export default class BmfontAssembler extends Assembler2D { - _quadsUpdated (comp) {} - - _reserveQuads () {} --} -\ No newline at end of file -+} -diff --git a/engine/cocos2d/core/renderer/utils/label/ttf.js b/engine/cocos2d/core/renderer/utils/label/ttf.js -index 49d90fa..f5f8232 100644 ---- a/engine/cocos2d/core/renderer/utils/label/ttf.js -+++ b/engine/cocos2d/core/renderer/utils/label/ttf.js -@@ -55,6 +55,8 @@ let _fontFamily = ''; - let _overflow = Overflow.NONE; - let _isWrapText = false; - let _premultiply = false; -+let _isRetina = false; -+let _retinaScale = 1; - - // outline - let _outlineComp = null; -@@ -115,6 +117,12 @@ export default class TTFAssembler extends Assembler2D { - } - - _updateRenderData(comp) { -+ if (_isRetina) { -+ _fontSize /= _retinaScale; -+ _nodeContentSize.width /= _retinaScale; -+ _nodeContentSize.height /= _retinaScale; -+ } -+ - comp._actualFontSize = _fontSize; - comp.node.setContentSize(_nodeContentSize); - -@@ -127,6 +135,10 @@ export default class TTFAssembler extends Assembler2D { - _texture = null; - } - -+ getTTFTextureSizeScale() { -+ return _isRetina ? _retinaScale : 1; -+ } -+ - updateVerts () { - } - -@@ -136,6 +148,9 @@ export default class TTFAssembler extends Assembler2D { - _contentSizeExtend.width = _contentSizeExtend.height = 0; - if (_outlineComp) { - outlineWidth = _outlineComp.width; -+ if (_isRetina) { -+ outlineWidth *= _retinaScale; -+ } - top = bottom = left = right = outlineWidth; - _contentSizeExtend.width = _contentSizeExtend.height = outlineWidth * 2; - } -@@ -164,15 +179,27 @@ export default class TTFAssembler extends Assembler2D { - _canvas = assemblerData.canvas; - _texture = comp._frame._original ? comp._frame._original._texture : comp._frame._texture; - -+ _isRetina = (cc.sp.enableLabelRetina && comp.enableRetina === 0) || comp.enableRetina === 1; -+ _retinaScale = cc.sp.labelRetinaScale; - _string = comp.string.toString(); - _fontSize = comp._fontSize; -+ _nodeContentSize = comp.node.getContentSize(); -+ _lineHeight = comp._lineHeight; - _drawFontSize = _fontSize; - _underlineThickness = comp.underlineHeight || _drawFontSize / 8; -+ -+ if (_isRetina) { -+ _fontSize *= _retinaScale; -+ _nodeContentSize.width *= _retinaScale; -+ _nodeContentSize.height *= _retinaScale; -+ _lineHeight *= _retinaScale; -+ if (comp.underlineHeight) _underlineThickness *= _retinaScale; -+ _drawFontSize = _fontSize; -+ } -+ - _overflow = comp.overflow; -- _canvasSize.width = comp.node.width; -- _canvasSize.height = comp.node.height; -- _nodeContentSize = comp.node.getContentSize(); -- _lineHeight = comp._lineHeight; -+ _canvasSize.width = _nodeContentSize.width; -+ _canvasSize.height = _nodeContentSize.height; - _hAlign = comp.horizontalAlign; - _vAlign = comp.verticalAlign; - _color = comp.node.color; -@@ -248,14 +275,14 @@ export default class TTFAssembler extends Assembler2D { - - _setupOutline () { - _context.strokeStyle = `rgba(${_outlineColor.r}, ${_outlineColor.g}, ${_outlineColor.b}, ${_outlineColor.a / 255})`; -- _context.lineWidth = _outlineComp.width * 2; -+ _context.lineWidth = _outlineComp.width * 2 * (_isRetina ? _retinaScale : 1); - } - - _setupShadow () { - _context.shadowColor = `rgba(${_shadowColor.r}, ${_shadowColor.g}, ${_shadowColor.b}, ${_shadowColor.a / 255})`; -- _context.shadowBlur = _shadowComp.blur; -- _context.shadowOffsetX = _shadowComp.offset.x; -- _context.shadowOffsetY = -_shadowComp.offset.y; -+ _context.shadowBlur = _shadowComp.blur * (_isRetina ? _retinaScale : 1); -+ _context.shadowOffsetX = _shadowComp.offset.x * (_isRetina ? _retinaScale : 1); -+ _context.shadowOffsetY = -_shadowComp.offset.y * (_isRetina ? _retinaScale : 1); - } - - _drawTextEffect (startPosition, lineHeight) { -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 ac90d01..be7d330 100644 ---- a/engine/cocos2d/core/renderer/webgl/assemblers/label/2d/bmfont.js -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/label/2d/bmfont.js -@@ -121,6 +121,11 @@ export default class WebglBmfontAssembler extends BmfontAssembler { - - - // positions -+ const retinaScale = this.getTTFTextureSizeScale(); -+ x /= retinaScale; -+ y /= retinaScale; -+ rectWidth /= retinaScale; -+ rectHeight /= retinaScale; - l = x; - r = x + rectWidth * scale; - b = y - rectHeight * scale; -diff --git a/engine/cocos2d/core/renderer/webgl/assemblers/label/2d/ttf.js b/engine/cocos2d/core/renderer/webgl/assemblers/label/2d/ttf.js -index e073440..e34d1f6 100644 ---- a/engine/cocos2d/core/renderer/webgl/assemblers/label/2d/ttf.js -+++ b/engine/cocos2d/core/renderer/webgl/assemblers/label/2d/ttf.js -@@ -49,10 +49,11 @@ export default class WebglTTFAssembler extends TTFAssembler { - super.updateColor(comp, color); - } - -- updateVerts (comp) { -+ updateVerts(comp) { -+ const scale = this.getTTFTextureSizeScale(); - let node = comp.node, -- canvasWidth = comp._ttfTexture.width, -- canvasHeight = comp._ttfTexture.height, -+ canvasWidth = comp._ttfTexture.width / scale, -+ canvasHeight = comp._ttfTexture.height / scale, - appx = node.anchorX * node.width, - appy = node.anchorY * node.height; - --- -2.32.0 (Apple Git-132) - diff --git a/patches/v1.0.0/0009-Char.patch b/patches/v1.0.0/0009-Char.patch deleted file mode 100644 index 4abf7fcc..00000000 --- a/patches/v1.0.0/0009-Char.patch +++ /dev/null @@ -1,619 +0,0 @@ -From 29ab0105fffc4316b06eab3e4834e5675b730259 Mon Sep 17 00:00:00 2001 -From: SmallMain -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) - diff --git a/patches/v1.0.0/0010-Spine-region-API.patch b/patches/v1.0.0/0010-Spine-region-API.patch deleted file mode 100644 index 20dcfd24..00000000 --- a/patches/v1.0.0/0010-Spine-region-API.patch +++ /dev/null @@ -1,799 +0,0 @@ -From 311adb9248bd23ed8fe5d282b8c1aa02b5d0cfba Mon Sep 17 00:00:00 2001 -From: SmallMain -Date: Tue, 21 Jun 2022 12:01:39 +0800 -Subject: [PATCH 10/16] =?UTF-8?q?Spine=20=E7=BB=84=E4=BB=B6=E6=94=AF?= - =?UTF-8?q?=E6=8C=81=E5=A4=9A=E7=BA=B9=E7=90=86=E6=B8=B2=E6=9F=93=E3=80=81?= - =?UTF-8?q?=E5=8A=A8=E6=80=81=E5=9B=BE=E9=9B=86=E3=80=81=E4=B8=8E=E5=85=B6?= - =?UTF-8?q?=E5=AE=83=E7=BB=84=E4=BB=B6=E5=90=88=E6=89=B9=E3=80=81region=20?= - =?UTF-8?q?=E6=8D=A2=E8=A3=85=E5=B9=B6=E5=A2=9E=E5=8A=A0=E6=8D=A2=E8=A3=85?= - =?UTF-8?q?=E7=9B=B8=E5=85=B3=E7=9A=84=20API=20=E6=8E=A5=E5=8F=A3?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - ---- - engine/cocos2d/core/assets/CCSpriteFrame.js | 1 + - .../core/renderer/webgl/mesh-buffer.js | 46 +++ - engine/extensions/spine/Skeleton.js | 68 ++++- - engine/extensions/spine/lib/spine.js | 14 +- - engine/extensions/spine/skeleton-data.js | 114 ++++++- - engine/extensions/spine/spine-assembler.js | 278 ++++++++++++++---- - 6 files changed, 455 insertions(+), 66 deletions(-) - -diff --git a/engine/cocos2d/core/assets/CCSpriteFrame.js b/engine/cocos2d/core/assets/CCSpriteFrame.js -index 37837bd..7038378 100644 ---- a/engine/cocos2d/core/assets/CCSpriteFrame.js -+++ b/engine/cocos2d/core/assets/CCSpriteFrame.js -@@ -651,6 +651,7 @@ let SpriteFrame = cc.Class(/** @lends cc.SpriteFrame# */{ - this._texture = this._original._texture; - this._original = null; - this._calculateUV(); -+ this.emit("_resetDynamicAtlasFrame"); - }, - - _calculateUV () { -diff --git a/engine/cocos2d/core/renderer/webgl/mesh-buffer.js b/engine/cocos2d/core/renderer/webgl/mesh-buffer.js -index f8d300f..d0a998f 100644 ---- a/engine/cocos2d/core/renderer/webgl/mesh-buffer.js -+++ b/engine/cocos2d/core/renderer/webgl/mesh-buffer.js -@@ -187,6 +187,52 @@ let MeshBuffer = cc.Class({ - this.requestStatic(vertexCount, indiceCount); - return this._offsetInfo; - }, -+ -+ requestForSpine(vertexCount, indiceCount) { -+ if (this._batcher._buffer !== this) { -+ this._batcher._flush(); -+ this._batcher._buffer = this; -+ } -+ -+ this.requestStaticForSpine(vertexCount, indiceCount); -+ return this._offsetInfo; -+ }, -+ -+ requestStaticForSpine(vertexCount, indiceCount) { -+ -+ this.checkAndSwitchBuffer(vertexCount); -+ -+ let byteOffset = this.byteOffset + vertexCount * this._vertexBytes; -+ let indiceOffset = this.indiceOffset + indiceCount; -+ -+ let byteLength = this._vData.byteLength; -+ let indiceLength = this._iData.length; -+ if (byteOffset > byteLength || indiceOffset > indiceLength) { -+ while (byteLength < byteOffset || indiceLength < indiceOffset) { -+ this._initVDataCount *= 2; -+ this._initIDataCount *= 2; -+ -+ byteLength = this._initVDataCount * 4; -+ indiceLength = this._initIDataCount; -+ } -+ -+ this._reallocBuffer(); -+ } -+ -+ let offsetInfo = this._offsetInfo; -+ offsetInfo.vertexOffset = this.vertexOffset; -+ offsetInfo.indiceOffset = this.indiceOffset; -+ offsetInfo.byteOffset = this.byteOffset; -+ }, -+ -+ adjustForSpine(vertexCount, indiceCount) { -+ this.vertexOffset += vertexCount; -+ this.indiceOffset += indiceCount; -+ -+ this.byteOffset = this.byteOffset + vertexCount * this._vertexBytes; -+ -+ this._dirty = true; -+ }, - - _reallocBuffer () { - this._reallocVData(true); -diff --git a/engine/extensions/spine/Skeleton.js b/engine/extensions/spine/Skeleton.js -index da54c8c..42046fc 100644 ---- a/engine/extensions/spine/Skeleton.js -+++ b/engine/extensions/spine/Skeleton.js -@@ -427,7 +427,16 @@ sp.Skeleton = cc.Class({ - // Play times - _playTimes : 0, - // Is animation complete. -- _isAniComplete : true, -+ _isAniComplete: true, -+ -+ autoSwitchMaterial: { -+ type: RenderComponent.EnableType, -+ default: RenderComponent.EnableType.GLOBAL, -+ }, -+ allowDynamicAtlas: { -+ type: RenderComponent.EnableType, -+ default: RenderComponent.EnableType.GLOBAL, -+ }, - }, - - // CONSTRUCTOR -@@ -443,6 +452,7 @@ sp.Skeleton = cc.Class({ - this._startEntry = {animation : {name : ""}, trackIndex : 0}; - this._endEntry = {animation : {name : ""}, trackIndex : 0}; - this.attachUtil = new AttachUtil(); -+ this._dataDirty = true; - }, - - // override base class _getDefaultMaterial to modify default material -@@ -455,8 +465,11 @@ sp.Skeleton = cc.Class({ - let useTint = this.useTint || (this.isAnimationCached() && !CC_NATIVERENDERER); - let baseMaterial = this.getMaterial(0); - if (baseMaterial) { -- baseMaterial.define('USE_TINT', useTint); -- baseMaterial.define('CC_USE_MODEL', !this.enableBatch); -+ const isMultiSupport = baseMaterial.material.isMultiSupport(); -+ if (!isMultiSupport) { -+ baseMaterial.define('USE_TINT', useTint); -+ baseMaterial.define('CC_USE_MODEL', !this.enableBatch); -+ } - - let srcBlendFactor = this.premultipliedAlpha ? cc.gfx.BLEND_ONE : cc.gfx.BLEND_SRC_ALPHA; - let dstBlendFactor = cc.gfx.BLEND_ONE_MINUS_SRC_ALPHA; -@@ -468,6 +481,11 @@ sp.Skeleton = cc.Class({ - cc.gfx.BLEND_FUNC_ADD, - dstBlendFactor, dstBlendFactor - ); -+ -+ if (isMultiSupport) { -+ if (this.useTint) this.useTint = false; -+ if (!this.enableBatch) this.enableBatch = true; -+ } - } - this._materialCache = {}; - }, -@@ -493,7 +511,11 @@ sp.Skeleton = cc.Class({ - let baseMaterial = this.getMaterial(0); - if (baseMaterial) { - let useTint = this.useTint || (this.isAnimationCached() && !CC_NATIVERENDERER); -- baseMaterial.define('USE_TINT', useTint); -+ if (!baseMaterial.material.isMultiSupport()) { -+ baseMaterial.define('USE_TINT', useTint); -+ } else { -+ if (this.useTint) this.useTint = false; -+ } - } - this._materialCache = {}; - }, -@@ -502,7 +524,11 @@ sp.Skeleton = cc.Class({ - _updateBatch () { - let baseMaterial = this.getMaterial(0); - if (baseMaterial) { -- baseMaterial.define('CC_USE_MODEL', !this.enableBatch); -+ if (!baseMaterial.material.isMultiSupport()) { -+ baseMaterial.define('CC_USE_MODEL', !this.enableBatch); -+ } else { -+ if (!this.enableBatch) this.enableBatch = true; -+ } - } - this._materialCache = {}; - }, -@@ -955,6 +981,37 @@ sp.Skeleton = cc.Class({ - this.invalidAnimationCache(); - }, - -+ /** -+ * 获取 attachment 的 region -+ */ -+ getRegion(slotName, attachmentName) { -+ const attachment = this.getAttachment(slotName, attachmentName); -+ if (attachment) { -+ return attachment.region; -+ } -+ return null; -+ }, -+ -+ /** -+ * 修改 attachment 的 region -+ */ -+ setRegion(slotName, attachmentName, region) { -+ const attachment = this.getAttachment(slotName, attachmentName); -+ if (attachment) { -+ attachment.region = region; -+ if (attachment instanceof sp.spine.MeshAttachment) { -+ attachment.updateUVs(); -+ } else if (attachment instanceof sp.spine.RegionAttachment) { -+ attachment.setRegion(region); -+ attachment.updateOffset(); -+ } -+ this._dataDirty = true; -+ this.invalidAnimationCache(); -+ return true; -+ } -+ return false; -+ }, -+ - /** - * Return the renderer of attachment. - * @method getTextureAtlas -@@ -1335,6 +1392,7 @@ sp.Skeleton = cc.Class({ - this.attachUtil._associateAttachedNode(); - this._preCacheMode = this._cacheMode; - this.animation = this.defaultAnimation; -+ this._dataDirty = true; - }, - - _refreshInspector () { -diff --git a/engine/extensions/spine/lib/spine.js b/engine/extensions/spine/lib/spine.js -index 857b433..fa12640 100644 ---- a/engine/extensions/spine/lib/spine.js -+++ b/engine/extensions/spine/lib/spine.js -@@ -8004,7 +8004,7 @@ var spine; - RegionAttachment.prototype.setRegion = function (region) { - this.region = region; - var uvs = this.uvs; -- if (region.rotate) { -+ if (region.degrees === 90) { - uvs[2] = region.u; - uvs[3] = region.v2; - uvs[4] = region.u; -@@ -8013,8 +8013,16 @@ var spine; - uvs[7] = region.v; - uvs[0] = region.u2; - uvs[1] = region.v2; -- } -- else { -+ } else if (region.degrees === 270) { -+ uvs[6] = region.u; -+ uvs[7] = region.v2; -+ uvs[0] = region.u; -+ uvs[1] = region.v; -+ uvs[2] = region.u2; -+ uvs[3] = region.v; -+ uvs[4] = region.u2; -+ uvs[5] = region.v2; -+ } else { - uvs[0] = region.u; - uvs[1] = region.v2; - uvs[2] = region.u; -diff --git a/engine/extensions/spine/skeleton-data.js b/engine/extensions/spine/skeleton-data.js -index a7bdb10..9f233ed 100644 ---- a/engine/extensions/spine/skeleton-data.js -+++ b/engine/extensions/spine/skeleton-data.js -@@ -139,6 +139,74 @@ let SkeletonData = cc.Class({ - - statics: { - preventDeferredLoadDependents: true, -+ -+ createRegion(spriteFrame, original = undefined) { -+ const region = new sp.spine.TextureAtlasRegion(); -+ -+ const texture = spriteFrame.getTexture(); -+ const rect = spriteFrame.getRect(); -+ const origSize = spriteFrame.getOriginalSize(); -+ const _offset = spriteFrame.getOffset(); -+ const rotate = spriteFrame.isRotated(); -+ const offset = cc.v2( -+ (origSize.width - rect.width) * 0.5 + _offset.x, -+ (origSize.height - rect.height) * 0.5 + _offset.y, -+ ); -+ const degrees = rotate ? 270 : 0; -+ -+ if (original) { -+ region.name = original.name; -+ region.page = original.page; -+ } -+ -+ region.x = rect.x; -+ region.y = rect.y; -+ region.width = rect.width; -+ region.height = rect.height; -+ region.originalWidth = origSize.width; -+ region.originalHeight = origSize.height; -+ region.offsetX = offset.x; -+ region.offsetY = offset.y; -+ region.rotate = degrees != 0; -+ region.degrees = degrees; -+ -+ const skelTex = new sp.SkeletonTexture({ -+ width: texture.width, -+ height: texture.height, -+ }); -+ skelTex.setRealTexture(texture); -+ region.texture = skelTex; -+ -+ this.updateRegionUV(region); -+ -+ return region; -+ }, -+ -+ updateRegionUV(region) { -+ const texture = region.texture._texture; -+ if (region.rotate) { -+ region.u = region.x / texture.width; -+ region.v = region.y / texture.height; -+ region.u2 = (region.x + region.height) / texture.width; -+ region.v2 = (region.y + region.width) / texture.height; -+ } else { -+ region.u = region.x / texture.width; -+ region.v = region.y / texture.height; -+ region.u2 = (region.x + region.width) / texture.width; -+ region.v2 = (region.y + region.height) / texture.height; -+ } -+ }, -+ -+ createSpriteFrame(region) { -+ const frame = new cc.SpriteFrame( -+ region.texture._texture, -+ cc.rect(region.x, region.y, region.width, region.height), -+ region.rotate, // 如果 region 不是 0 或 270 则会出现问题 -+ cc.v2(region.offsetX - (region.originalWidth - region.width) * 0.5, region.offsetY - (region.originalHeight - region.height) * 0.5), -+ cc.size(region.originalWidth, region.originalHeight), -+ ); -+ return frame; -+ }, - }, - - // PUBLIC -@@ -166,6 +234,7 @@ let SkeletonData = cc.Class({ - this._skinsEnum = null; - this._animsEnum = null; - } -+ this._cloneId = 0; - }, - - ensureTexturesLoaded (loaded, caller) { -@@ -322,7 +391,50 @@ let SkeletonData = cc.Class({ - return this._atlasCache = new sp.spine.TextureAtlas(this.atlasText, this._getTexture.bind(this)); - }, - -- destroy () { -+ /** -+ * 克隆 SkeletonData -+ */ -+ clone: function () { -+ const cloned = new SkeletonData(); -+ cloned._cloneId = this._cloneId + 1; -+ const suffix = '(clone ' + String(cloned._cloneId) + ')'; -+ cloned._uuid = this._uuid + suffix; -+ cloned.name = this.name + suffix; -+ cloned.scale = this.scale; -+ cloned.textureNames = this.textureNames; -+ cloned.textures = this.textures; -+ cloned._atlasText = this._atlasText; -+ cloned._skeletonJson = this._skeletonJson; -+ cloned._buffer = this._buffer; -+ -+ return cloned; -+ }, -+ -+ destroy() { -+ // 删除动态图集 -+ if (this._atlasCache) { -+ const regions = this._atlasCache.regions; -+ for (const region of regions) { -+ if (region._spriteFrame) { -+ region._spriteFrame.destroy(); -+ region._spriteFrame = null; -+ } -+ } -+ } -+ if (this._skeletonCache) { -+ const skins = this._skeletonCache.skins; -+ for (const skin of skins) { -+ for (const attachments of skin.attachments) { -+ for (const key in attachments) { -+ const region = attachments[key].region; -+ if (region && region._spriteFrame) { -+ region._spriteFrame.destroy(); -+ region._spriteFrame = null; -+ } -+ } -+ } -+ } -+ } - SkeletonCache.removeSkeleton(this._uuid); - this._super(); - }, -diff --git a/engine/extensions/spine/spine-assembler.js b/engine/extensions/spine/spine-assembler.js -index 652af54..36c91f0 100644 ---- a/engine/extensions/spine/spine-assembler.js -+++ b/engine/extensions/spine/spine-assembler.js -@@ -30,6 +30,7 @@ const spine = require('./lib/spine'); - const RenderFlow = require('../../cocos2d/core/renderer/render-flow'); - const VertexFormat = require('../../cocos2d/core/renderer/webgl/vertex-format') - const VFOneColor = VertexFormat.vfmtPosUvColor; -+const VFOneColorTexId = VertexFormat.vfmtPosUvColorTexId; - const VFTwoColor = VertexFormat.vfmtPosUvTwoColor; - const gfx = cc.gfx; - -@@ -58,6 +59,8 @@ let _multiplier; - let _slotRangeStart; - let _slotRangeEnd; - let _useTint; -+let _useMulti; -+let _texId; - let _debugSlots; - let _debugBones; - let _debugMesh; -@@ -105,34 +108,67 @@ function _getSlotMaterial (tex, blendMode) { - let baseMaterial = _comp._materials[0]; - if (!baseMaterial) return null; - -- // The key use to find corresponding material -- let key = tex.getId() + src + dst + _useTint + useModel; -- let materialCache = _comp._materialCache; -- let material = materialCache[key]; -- if (!material) { -- if (!materialCache.baseMaterial) { -- material = baseMaterial; -- materialCache.baseMaterial = baseMaterial; -- } else { -- material = cc.MaterialVariant.create(baseMaterial); -+ if (_useMulti) { -+ let key = tex.getId() + src + dst; -+ let materialCache = _comp._materialCache; -+ let materialInfo = materialCache[key]; -+ if (!materialInfo) { -+ let texId = baseMaterial.material.getMultiHandler().getIndex(tex.getImpl()); -+ if (!materialCache.baseMaterial) { -+ materialInfo = { material: baseMaterial, texId: texId }; -+ materialCache.baseMaterial = materialInfo; -+ } else { -+ materialInfo = { material: cc.MaterialVariant.create(baseMaterial), texId: texId }; -+ } -+ -+ if (texId === -1) { -+ materialInfo.material.setProperty('texture', tex); -+ materialInfo.texId = 0; -+ } -+ -+ // update blend function -+ materialInfo.material.setBlend( -+ true, -+ gfx.BLEND_FUNC_ADD, -+ src, dst, -+ gfx.BLEND_FUNC_ADD, -+ src, dst -+ ); -+ materialCache[key] = materialInfo; - } -- -- material.define('CC_USE_MODEL', useModel); -- material.define('USE_TINT', _useTint); -- // update texture -- material.setProperty('texture', tex); -- -- // update blend function -- material.setBlend( -- true, -- gfx.BLEND_FUNC_ADD, -- src, dst, -- gfx.BLEND_FUNC_ADD, -- src, dst -- ); -- materialCache[key] = material; -+ _texId = materialInfo.texId; -+ return materialInfo.material; -+ } else { -+ // The key use to find corresponding material -+ let key = tex.getId() + src + dst + _useTint + useModel; -+ let materialCache = _comp._materialCache; -+ let material = materialCache[key]; -+ if (!material) { -+ if (!materialCache.baseMaterial) { -+ material = baseMaterial; -+ materialCache.baseMaterial = baseMaterial; -+ } else { -+ material = cc.MaterialVariant.create(baseMaterial); -+ } -+ -+ material.define('CC_USE_MODEL', useModel); -+ material.define('USE_TINT', _useTint); -+ // update texture -+ material.setProperty('texture', tex); -+ -+ // update blend function -+ material.setBlend( -+ true, -+ gfx.BLEND_FUNC_ADD, -+ src, dst, -+ gfx.BLEND_FUNC_ADD, -+ src, dst -+ ); -+ materialCache[key] = material; -+ } -+ -+ return material; - } -- return material; - } - - function _handleColor (color) { -@@ -162,12 +198,112 @@ function _spineColorToInt32 (spineColor) { - export default class SpineAssembler extends Assembler { - updateRenderData (comp) { - if (comp.isAnimationCached()) return; -+ -+ if (comp._dataDirty) { -+ // 自动合图 -+ this.packDynamicAtlasForSpine(comp); -+ -+ // 自动切换材质 -+ const autoSwitchMaterial = comp.autoSwitchMaterial; -+ if ((cc.sp.autoSwitchMaterial && autoSwitchMaterial === 0) || autoSwitchMaterial === 1) { -+ const material = comp._materials[0]; -+ if (!material) return false; -+ -+ const skins = comp.skeletonData._skeletonCache.skins; -+ for (const skin of skins) { -+ for (const attachment of skin.attachments) { -+ for (const key in attachment) { -+ const region = attachment[key].region; -+ if (region && region.texture) { -+ this.checkAndSwitchMaterial(comp, region.texture._texture, material); -+ break; -+ } -+ } -+ } -+ } -+ } -+ comp._dataDirty = false; -+ } -+ - let skeleton = comp._skeleton; - if (skeleton) { - skeleton.updateWorldTransform(); - } - } - -+ packDynamicAtlasForSpine(comp) { -+ if (CC_TEST) return false; -+ -+ const allowDynamicAtlas = comp.allowDynamicAtlas; -+ if ((cc.sp.allowDynamicAtlas && allowDynamicAtlas === 0) || allowDynamicAtlas === 1) { -+ if (cc.dynamicAtlasManager) { -+ const skins = comp.skeletonData._skeletonCache.skins; -+ for (const skin of skins) { -+ for (const attachments of skin.attachments) { -+ for (const key in attachments) { -+ const attachment = attachments[key]; -+ const region = attachment.region; -+ if (region && !region._original && region.texture && region.texture._texture.packable) { -+ if (region._spriteFrame) { -+ region._spriteFrame.destroy(); -+ region._spriteFrame = null; -+ } -+ const frame = sp.SkeletonData.createSpriteFrame(region); -+ const packedFrame = cc.dynamicAtlasManager.insertSpriteFrame(frame); -+ if (packedFrame) { -+ frame._setDynamicAtlasFrame(packedFrame); -+ -+ region._original = { -+ _texture: region.texture, -+ _x: region.x, -+ _y: region.y, -+ }; -+ -+ region.texture = new sp.SkeletonTexture({ -+ width: packedFrame.texture.width, -+ height: packedFrame.texture.height, -+ }); -+ region.texture.setRealTexture(packedFrame.texture); -+ -+ region.x = packedFrame.x; -+ region.y = packedFrame.y; -+ -+ // update uv -+ sp.SkeletonData.updateRegionUV(region); -+ if (attachment instanceof sp.spine.MeshAttachment) { -+ attachment.updateUVs(); -+ } else { -+ attachment.setRegion(region); -+ attachment.updateOffset(); -+ } -+ -+ frame.once("_resetDynamicAtlasFrame", () => { -+ region.x = region._original._x; -+ region.y = region._original._y; -+ region.texture = region._original._texture; -+ region._original = null; -+ -+ // update uv -+ sp.SkeletonData.updateRegionUV(region); -+ if (attachment instanceof sp.spine.MeshAttachment) { -+ attachment.updateUVs(); -+ } else { -+ attachment.setRegion(region); -+ attachment.updateOffset(); -+ } -+ }); -+ region._spriteFrame = frame; -+ } else { -+ frame.destroy(); -+ } -+ } -+ } -+ } -+ } -+ } -+ } -+ } -+ - fillVertices (skeletonColor, attachmentColor, slotColor, clipper, slot) { - - let vbuf = _buffer._vData, -@@ -207,16 +343,24 @@ export default class SpineAssembler extends Assembler { - vbuf[v + 1] = _tempPos.y; // y - vbuf[v + 2] = _tempUv.x; // u - vbuf[v + 3] = _tempUv.y; // v -- uintVData[v + 4] = _spineColorToInt32(_finalColor); // light color -- _useTint && (uintVData[v + 5] = _spineColorToInt32(_darkColor)); // dark color -+ uintVData[v + 4] = _spineColorToInt32(_finalColor); // light color -+ if (_useMulti) { -+ vbuf[v + 5] = _texId; -+ } else { -+ _useTint && (uintVData[v + 5] = _spineColorToInt32(_darkColor)); // dark color -+ } - } - } else { - _finalColor32 = _spineColorToInt32(_finalColor); - _darkColor32 = _spineColorToInt32(_darkColor); - - for (let v = _vertexFloatOffset, n = _vertexFloatOffset + _vertexFloatCount; v < n; v += _perVertexSize) { -- uintVData[v + 4] = _finalColor32; // light color -- _useTint && (uintVData[v + 5] = _darkColor32); // dark color -+ uintVData[v + 4] = _finalColor32; // light color -+ if (_useMulti) { -+ vbuf[v + 5] = _texId; -+ } else { -+ _useTint && (uintVData[v + 5] = _darkColor32); // dark color -+ } - } - } - } else { -@@ -229,7 +373,7 @@ export default class SpineAssembler extends Assembler { - _indexCount = clippedTriangles.length; - _vertexFloatCount = clippedVertices.length / _perClipVertexSize * _perVertexSize; - -- offsetInfo = _buffer.request(_vertexFloatCount / _perVertexSize, _indexCount); -+ offsetInfo = _buffer.requestForSpine(_vertexFloatCount / _perVertexSize, _indexCount); - _indexOffset = offsetInfo.indiceOffset, - _vertexOffset = offsetInfo.vertexOffset, - _vertexFloatOffset = offsetInfo.byteOffset >> 2; -@@ -260,8 +404,12 @@ export default class SpineAssembler extends Assembler { - vbuf[offset + 2] = _tempUv.x; // u - vbuf[offset + 3] = _tempUv.y; // v - uintVData[offset + 4] = _spineColorToInt32(_finalColor); -- if (_useTint) { -- uintVData[offset + 5] = _spineColorToInt32(_darkColor); -+ if (_useMulti) { -+ vbuf[offset + 5] = _texId; -+ } else { -+ if (_useTint) { -+ uintVData[offset + 5] = _spineColorToInt32(_darkColor); -+ } - } - } - } else { -@@ -273,10 +421,13 @@ export default class SpineAssembler extends Assembler { - - _finalColor32 = ((clippedVertices[v + 5]<<24) >>> 0) + (clippedVertices[v + 4]<<16) + (clippedVertices[v + 3]<<8) + clippedVertices[v + 2]; - uintVData[offset + 4] = _finalColor32; -- -- if (_useTint) { -- _darkColor32 = ((clippedVertices[v + 11]<<24) >>> 0) + (clippedVertices[v + 10]<<16) + (clippedVertices[v + 9]<<8) + clippedVertices[v + 8]; -- uintVData[offset + 5] = _darkColor32; -+ if (_useMulti) { -+ vbuf[offset + 5] = _texId; -+ } else { -+ if (_useTint) { -+ _darkColor32 = ((clippedVertices[v + 11] << 24) >>> 0) + (clippedVertices[v + 10] << 16) + (clippedVertices[v + 9] << 8) + clippedVertices[v + 8]; -+ uintVData[offset + 5] = _darkColor32; -+ } - } - } - } -@@ -312,7 +463,7 @@ export default class SpineAssembler extends Assembler { - } - - // x y u v r1 g1 b1 a1 r2 g2 b2 a2 or x y u v r g b a -- _perClipVertexSize = _useTint ? 12 : 8; -+ _perClipVertexSize = _useMulti ? 12 : (_useTint ? 12 : 8); - - _vertexFloatCount = 0; - _vertexFloatOffset = 0; -@@ -384,7 +535,7 @@ export default class SpineAssembler extends Assembler { - _vertexFloatCount = 4 * _perVertexSize; - _indexCount = 6; - -- offsetInfo = _buffer.request(4, 6); -+ offsetInfo = _buffer.requestForSpine(4, 6); - _indexOffset = offsetInfo.indiceOffset, - _vertexOffset = offsetInfo.vertexOffset, - _vertexFloatOffset = offsetInfo.byteOffset >> 2; -@@ -413,7 +564,7 @@ export default class SpineAssembler extends Assembler { - _vertexFloatCount = (attachment.worldVerticesLength >> 1) * _perVertexSize; - _indexCount = triangles.length; - -- offsetInfo = _buffer.request(_vertexFloatCount / _perVertexSize, _indexCount); -+ offsetInfo = _buffer.requestForSpine(_vertexFloatCount / _perVertexSize, _indexCount); - _indexOffset = offsetInfo.indiceOffset, - _vertexOffset = offsetInfo.vertexOffset, - _vertexFloatOffset = offsetInfo.byteOffset >> 2; -@@ -485,7 +636,7 @@ export default class SpineAssembler extends Assembler { - vbuf[ii + 1] = _x * _m01 + _y * _m05 + _m13; - } - } -- _buffer.adjust(_vertexFloatCount / _perVertexSize, _indexCount); -+ _buffer.adjustForSpine(_vertexFloatCount / _perVertexSize, _indexCount); - } - - clipper.clipEndWithSlot(slot); -@@ -569,7 +720,7 @@ export default class SpineAssembler extends Assembler { - _vertexCount = segInfo.vertexCount; - _indexCount = segInfo.indexCount; - -- offsetInfo = _buffer.request(_vertexCount, _indexCount); -+ offsetInfo = _buffer.requestForSpine(_vertexCount, _indexCount); - _indexOffset = offsetInfo.indiceOffset; - _vertexOffset = offsetInfo.vertexOffset; - _vfOffset = offsetInfo.byteOffset >> 2; -@@ -599,19 +750,28 @@ export default class SpineAssembler extends Assembler { - } - } - -- _buffer.adjust(_vertexCount, _indexCount); -- if ( !_needColor ) continue; -+ _buffer.adjustForSpine(_vertexCount, _indexCount); - -- // handle color -- let frameColorOffset = frameVFOffset - segVFCount; -- for (let ii = _vfOffset + 4, il = _vfOffset + 4 + segVFCount; ii < il; ii += 6, frameColorOffset += 6) { -- if (frameColorOffset >= maxVFOffset) { -- nowColor = colors[colorOffset++]; -- _handleColor(nowColor); -- maxVFOffset = nowColor.vfOffset; -+ if (_needColor) { -+ // handle color -+ let frameColorOffset = frameVFOffset - segVFCount; -+ for (let ii = _vfOffset + 4, il = _vfOffset + 4 + segVFCount; ii < il; ii += 6, frameColorOffset += 6) { -+ if (frameColorOffset >= maxVFOffset) { -+ nowColor = colors[colorOffset++]; -+ _handleColor(nowColor); -+ maxVFOffset = nowColor.vfOffset; -+ } -+ uintbuf[ii] = _finalColor32; -+ if (_useMulti) { -+ vbuf[ii + 1] = _texId; -+ } else { -+ uintbuf[ii + 1] = _darkColor32; -+ } -+ } -+ } else if (_useMulti) { -+ for (let ii = _vfOffset + 4, il = _vfOffset + 4 + segVFCount; ii < il; ii += 6) { -+ vbuf[ii + 1] = _texId; - } -- uintbuf[ii] = _finalColor32; -- uintbuf[ii + 1] = _darkColor32; - } - } - } -@@ -628,13 +788,17 @@ export default class SpineAssembler extends Assembler { - _nodeB = nodeColor.b / 255; - _nodeA = nodeColor.a / 255; - -- _useTint = comp.useTint || comp.isAnimationCached(); -- _vertexFormat = _useTint? VFTwoColor : VFOneColor; -+ let baseMaterial = comp._materials[0]; -+ if (!baseMaterial) return; -+ -+ _useMulti = baseMaterial.material.isMultiSupport(); -+ _useTint = !_useMulti && (comp.useTint || comp.isAnimationCached()); -+ _vertexFormat = _useMulti ? VFOneColorTexId : (_useTint ? VFTwoColor : VFOneColor); - // x y u v color1 color2 or x y u v color -- _perVertexSize = _useTint ? 6 : 5; -+ _perVertexSize = _useMulti ? 6 :(_useTint ? 6 : 5); - - _node = comp.node; -- _buffer = renderer.getBuffer('spine', _vertexFormat); -+ _buffer = renderer.getBuffer('mesh', _vertexFormat); - _renderer = renderer; - _comp = comp; - --- -2.32.0 (Apple Git-132) - diff --git a/patches/v1.0.0/0011-.patch b/patches/v1.0.0/0011-.patch deleted file mode 100644 index 77f3e538..00000000 --- a/patches/v1.0.0/0011-.patch +++ /dev/null @@ -1,146 +0,0 @@ -From 25a82582da7f743d769fbfb136bb4c5c9713e3e2 Mon Sep 17 00:00:00 2001 -From: SmallMain -Date: Tue, 21 Jun 2022 15:36:05 +0800 -Subject: [PATCH 11/16] =?UTF-8?q?=E5=A4=9A=E7=BA=B9=E7=90=86=E6=B8=B2?= - =?UTF-8?q?=E6=9F=93=E3=80=81=E5=8A=A8=E6=80=81=E5=9B=BE=E9=9B=86=E5=BC=80?= - =?UTF-8?q?=E5=85=B3=E6=97=B6=E4=B8=BB=E5=8A=A8=E5=88=B7=E6=96=B0=E6=B8=B2?= - =?UTF-8?q?=E6=9F=93=E7=8A=B6=E6=80=81?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - ---- - engine/cocos2d/core/components/CCLabel.js | 9 +++++++++ - .../cocos2d/core/components/CCMotionStreak.js | 12 ++++++++++++ - engine/cocos2d/core/components/CCSprite.js | 8 ++++++++ - engine/extensions/spine/Skeleton.js | 18 ++++++++++++++++-- - 4 files changed, 45 insertions(+), 2 deletions(-) - -diff --git a/engine/cocos2d/core/components/CCLabel.js b/engine/cocos2d/core/components/CCLabel.js -index b672f23..6cbfe1b 100644 ---- a/engine/cocos2d/core/components/CCLabel.js -+++ b/engine/cocos2d/core/components/CCLabel.js -@@ -586,15 +586,24 @@ let Label = cc.Class({ - autoSwitchMaterial: { - type: RenderComponent.EnableType, - default: RenderComponent.EnableType.GLOBAL, -+ notify(oldValue) { -+ if (this.autoSwitchMaterial === oldValue) return; -+ this.setVertsDirty(); -+ }, - }, - allowDynamicAtlas: { - type: RenderComponent.EnableType, - default: RenderComponent.EnableType.GLOBAL, -+ notify(oldValue) { -+ if (this.allowDynamicAtlas === oldValue) return; -+ this.setVertsDirty(); -+ }, - }, - enableRetina: { - type: RenderComponent.EnableType, - default: RenderComponent.EnableType.GLOBAL, - notify(oldValue) { -+ if (this.enableRetina === oldValue) return; - this.setVertsDirty(); - } - }, -diff --git a/engine/cocos2d/core/components/CCMotionStreak.js b/engine/cocos2d/core/components/CCMotionStreak.js -index 545c03f..7205e94 100644 ---- a/engine/cocos2d/core/components/CCMotionStreak.js -+++ b/engine/cocos2d/core/components/CCMotionStreak.js -@@ -218,9 +218,21 @@ var MotionStreak = cc.Class({ - autoSwitchMaterial: { - type: RenderComponent.EnableType, - default: RenderComponent.EnableType.GLOBAL, -+ notify(oldValue) { -+ if (this.autoSwitchMaterial === oldValue) return; -+ this.setVertsDirty(); -+ }, - }, - }, - -+ setVertsDirty() { -+ // 自动切换材质 -+ this._checkSwitchMaterial(); -+ -+ this._updateMaterial(); -+ this._super(); -+ }, -+ - __preload() { - this._super(); - this._checkSwitchMaterial(); -diff --git a/engine/cocos2d/core/components/CCSprite.js b/engine/cocos2d/core/components/CCSprite.js -index 806a50d..45debb3 100644 ---- a/engine/cocos2d/core/components/CCSprite.js -+++ b/engine/cocos2d/core/components/CCSprite.js -@@ -388,10 +388,18 @@ var Sprite = cc.Class({ - autoSwitchMaterial: { - type: RenderComponent.EnableType, - default: RenderComponent.EnableType.GLOBAL, -+ notify(oldValue) { -+ if (this.autoSwitchMaterial === oldValue) return; -+ this.setVertsDirty(); -+ }, - }, - allowDynamicAtlas: { - type: RenderComponent.EnableType, - default: RenderComponent.EnableType.GLOBAL, -+ notify(oldValue) { -+ if (this.allowDynamicAtlas === oldValue) return; -+ this.setVertsDirty(); -+ }, - }, - }, - -diff --git a/engine/extensions/spine/Skeleton.js b/engine/extensions/spine/Skeleton.js -index 42046fc..61cde65 100644 ---- a/engine/extensions/spine/Skeleton.js -+++ b/engine/extensions/spine/Skeleton.js -@@ -432,10 +432,18 @@ sp.Skeleton = cc.Class({ - autoSwitchMaterial: { - type: RenderComponent.EnableType, - default: RenderComponent.EnableType.GLOBAL, -+ notify(oldValue) { -+ if (this.autoSwitchMaterial === oldValue) return; -+ this.setVertsDirty(); -+ }, - }, - allowDynamicAtlas: { - type: RenderComponent.EnableType, - default: RenderComponent.EnableType.GLOBAL, -+ notify(oldValue) { -+ if (this.allowDynamicAtlas === oldValue) return; -+ this.setVertsDirty(); -+ }, - }, - }, - -@@ -455,6 +463,13 @@ sp.Skeleton = cc.Class({ - this._dataDirty = true; - }, - -+ setVertsDirty() { -+ this.invalidAnimationCache(); -+ this._dataDirty = true; -+ this._materialCache = {}; -+ this._super(); -+ }, -+ - // override base class _getDefaultMaterial to modify default material - _getDefaultMaterial () { - return cc.Material.getBuiltinMaterial('2d-spine'); -@@ -1005,8 +1020,7 @@ sp.Skeleton = cc.Class({ - attachment.setRegion(region); - attachment.updateOffset(); - } -- this._dataDirty = true; -- this.invalidAnimationCache(); -+ this.setVertsDirty(); - return true; - } - return false; --- -2.32.0 (Apple Git-132) - diff --git a/patches/v1.0.0/0012-cc.MotionStreak.patch b/patches/v1.0.0/0012-cc.MotionStreak.patch deleted file mode 100644 index 82cc5e82..00000000 --- a/patches/v1.0.0/0012-cc.MotionStreak.patch +++ /dev/null @@ -1,47 +0,0 @@ -From a0f89c84b0bfcaf32d81a621e863461eb83ace8b Mon Sep 17 00:00:00 2001 -From: SmallMain -Date: Tue, 21 Jun 2022 15:36:10 +0800 -Subject: [PATCH 12/16] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20cc.MotionStreak=20?= - =?UTF-8?q?=E9=83=A8=E5=88=86=E6=83=85=E5=86=B5=E4=B8=8B=E5=8D=A1=E6=AD=BB?= - =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - ---- - engine/cocos2d/core/components/CCMotionStreak.js | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/engine/cocos2d/core/components/CCMotionStreak.js b/engine/cocos2d/core/components/CCMotionStreak.js -index 7205e94..6e0eb3b 100644 ---- a/engine/cocos2d/core/components/CCMotionStreak.js -+++ b/engine/cocos2d/core/components/CCMotionStreak.js -@@ -242,6 +242,7 @@ var MotionStreak = cc.Class({ - if (this._assembler) { - const material = this._materials[0]; - if (!material) return; -+ if (!this._texture) return; - this._assembler.checkAndSwitchMaterial(this, this._texture, material); - } - }, -@@ -257,6 +258,7 @@ var MotionStreak = cc.Class({ - // 根据材质更新 uniform - const isMultiMaterial = material.material.isMultiSupport(); - if (isMultiMaterial) { -+ if (!this._texture) return; - this._updateMultiTexId(material, this._texture); - } else { - if (material.getProperty('texture') !== this._texture) { -@@ -272,7 +274,8 @@ var MotionStreak = cc.Class({ - } - - // texId -- if (isMultiMaterial && this._texIdDirty) { -+ if (isMultiMaterial && this._texIdDirty && this._assembler) { -+ if (!this._texture) return; - this._assembler.updateTexId(this); - this._texIdDirty = false; - } --- -2.32.0 (Apple Git-132) - diff --git a/patches/v1.0.0/0013-Spine.patch b/patches/v1.0.0/0013-Spine.patch deleted file mode 100644 index 23f0666f..00000000 --- a/patches/v1.0.0/0013-Spine.patch +++ /dev/null @@ -1,134 +0,0 @@ -From 6c742a9c7298f6c48d31c33c0407039a72903547 Mon Sep 17 00:00:00 2001 -From: SmallMain -Date: Tue, 21 Jun 2022 15:37:22 +0800 -Subject: [PATCH 13/16] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20Spine=20=E5=8D=95?= - =?UTF-8?q?=E5=8A=A8=E7=94=BB=E7=94=A8=E4=BA=86=E5=A4=9A=E4=B8=AA=E7=BA=B9?= - =?UTF-8?q?=E7=90=86=E6=97=B6=EF=BC=8C=E7=BC=93=E5=AD=98=E6=A8=A1=E5=BC=8F?= - =?UTF-8?q?=E4=B8=8B=E6=98=BE=E7=A4=BA=E9=94=99=E8=AF=AF=E7=9A=84=E9=97=AE?= - =?UTF-8?q?=E9=A2=98?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - ---- - engine/extensions/spine/Skeleton.js | 10 +++++++--- - engine/extensions/spine/skeleton-cache.js | 4 ++-- - engine/extensions/spine/spine-assembler.js | 18 +++++++++++------- - 3 files changed, 20 insertions(+), 12 deletions(-) - -diff --git a/engine/extensions/spine/Skeleton.js b/engine/extensions/spine/Skeleton.js -index 61cde65..b1eda9c 100644 ---- a/engine/extensions/spine/Skeleton.js -+++ b/engine/extensions/spine/Skeleton.js -@@ -464,8 +464,8 @@ sp.Skeleton = cc.Class({ - }, - - setVertsDirty() { -- this.invalidAnimationCache(); - this._dataDirty = true; -+ this.invalidAnimationCache(); - this._materialCache = {}; - this._super(); - }, -@@ -702,6 +702,8 @@ sp.Skeleton = cc.Class({ - - if (this.isAnimationCached()) { - -+ this._assembler.handleDynamicAtlasAndSwitchMaterial(this); -+ - // Cache mode and has animation queue. - if (this._isAniComplete) { - if (this._animationQueue.length === 0 && !this._headAniInfo) { -@@ -1086,6 +1088,7 @@ sp.Skeleton = cc.Class({ - if (this.attachUtil._hasAttachedNode()) { - this._frameCache.enableCacheAttachedInfo(); - } -+ this._assembler.handleDynamicAtlasAndSwitchMaterial(this); - this._frameCache.updateToFrame(0); - this._curFrame = this._frameCache.frames[0]; - } -@@ -1379,7 +1382,9 @@ sp.Skeleton = cc.Class({ - } - }, - -- _updateSkeletonData () { -+ _updateSkeletonData() { -+ this._dataDirty = true; -+ - if (!this.skeletonData) { - this.disableRender(); - return; -@@ -1406,7 +1411,6 @@ sp.Skeleton = cc.Class({ - this.attachUtil._associateAttachedNode(); - this._preCacheMode = this._cacheMode; - this.animation = this.defaultAnimation; -- this._dataDirty = true; - }, - - _refreshInspector () { -diff --git a/engine/extensions/spine/skeleton-cache.js b/engine/extensions/spine/skeleton-cache.js -index c0ef822..5a26e01 100644 ---- a/engine/extensions/spine/skeleton-cache.js -+++ b/engine/extensions/spine/skeleton-cache.js -@@ -423,8 +423,8 @@ let AnimationCache = cc.Class({ - } - - blendMode = slot.data.blendMode; -- if (_preTexUrl !== texture.nativeUrl || _preBlendMode !== blendMode) { -- _preTexUrl = texture.nativeUrl; -+ if (_preTexUrl !== texture._texture._id || _preBlendMode !== blendMode) { -+ _preTexUrl = texture._texture._id; - _preBlendMode = blendMode; - // Handle pre segment. - preSegOffset = _segOffset - 1; -diff --git a/engine/extensions/spine/spine-assembler.js b/engine/extensions/spine/spine-assembler.js -index 36c91f0..2744684 100644 ---- a/engine/extensions/spine/spine-assembler.js -+++ b/engine/extensions/spine/spine-assembler.js -@@ -199,6 +199,15 @@ export default class SpineAssembler extends Assembler { - updateRenderData (comp) { - if (comp.isAnimationCached()) return; - -+ this.handleDynamicAtlasAndSwitchMaterial(comp); -+ -+ let skeleton = comp._skeleton; -+ if (skeleton) { -+ skeleton.updateWorldTransform(); -+ } -+ } -+ -+ handleDynamicAtlasAndSwitchMaterial(comp) { - if (comp._dataDirty) { - // 自动合图 - this.packDynamicAtlasForSpine(comp); -@@ -210,13 +219,13 @@ export default class SpineAssembler extends Assembler { - if (!material) return false; - - const skins = comp.skeletonData._skeletonCache.skins; -- for (const skin of skins) { -+ root: for (const skin of skins) { - for (const attachment of skin.attachments) { - for (const key in attachment) { - const region = attachment[key].region; - if (region && region.texture) { - this.checkAndSwitchMaterial(comp, region.texture._texture, material); -- break; -+ break root; - } - } - } -@@ -224,11 +233,6 @@ export default class SpineAssembler extends Assembler { - } - comp._dataDirty = false; - } -- -- let skeleton = comp._skeleton; -- if (skeleton) { -- skeleton.updateWorldTransform(); -- } - } - - packDynamicAtlasForSpine(comp) { --- -2.32.0 (Apple Git-132) - diff --git a/patches/v1.0.0/0014-Char.patch b/patches/v1.0.0/0014-Char.patch deleted file mode 100644 index c8541e4b..00000000 --- a/patches/v1.0.0/0014-Char.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 44d365d4a46347fb179d12f1f53848deb2c4a336 Mon Sep 17 00:00:00 2001 -From: SmallMain -Date: Tue, 21 Jun 2022 22:36:31 +0800 -Subject: [PATCH 14/16] =?UTF-8?q?=E4=BC=98=E5=8C=96=20Char=20=E7=BC=93?= - =?UTF-8?q?=E5=AD=98=E6=A8=A1=E5=BC=8F=E7=9A=84=E6=80=A7=E8=83=BD=EF=BC=88?= - =?UTF-8?q?=E7=BA=B9=E7=90=86=E4=B8=8D=E9=9C=80=E8=A6=81=E5=88=A4=E6=96=AD?= - =?UTF-8?q?=E6=98=AF=E5=90=A6=E8=A6=81=E8=BF=98=E5=8E=9F=E5=8A=A8=E6=80=81?= - =?UTF-8?q?=E5=90=88=E5=9B=BE=EF=BC=89?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - ---- - engine/cocos2d/core/renderer/utils/label/letter-font.js | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/engine/cocos2d/core/renderer/utils/label/letter-font.js b/engine/cocos2d/core/renderer/utils/label/letter-font.js -index 0e7aaae..5e19af4 100644 ---- a/engine/cocos2d/core/renderer/utils/label/letter-font.js -+++ b/engine/cocos2d/core/renderer/utils/label/letter-font.js -@@ -119,7 +119,8 @@ LetterTexture.prototype = { - this._texture.handleLoadedTexture(); - }, - -- destroy () { -+ destroy() { -+ this._texture._packable = false; - this._texture.destroy(); - this._texture = null; - Label._canvasPool.put(this._data); --- -2.32.0 (Apple Git-132) - diff --git a/patches/v1.0.0/0015-Bitmap-uuid.patch b/patches/v1.0.0/0015-Bitmap-uuid.patch deleted file mode 100644 index 6cddb87f..00000000 --- a/patches/v1.0.0/0015-Bitmap-uuid.patch +++ /dev/null @@ -1,55 +0,0 @@ -From a4decd86188d65dbabd49aeeaaccc8713968d51a Mon Sep 17 00:00:00 2001 -From: SmallMain -Date: Tue, 21 Jun 2022 22:37:35 +0800 -Subject: [PATCH 15/16] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20Bitmap=20=E7=BC=93?= - =?UTF-8?q?=E5=AD=98=E6=A8=A1=E5=BC=8F=E5=A4=8D=E7=94=A8=E5=90=8E=E5=87=BA?= - =?UTF-8?q?=E7=8E=B0=E7=9A=84=E5=90=8C=20uuid=20=E5=AF=BC=E8=87=B4?= - =?UTF-8?q?=E6=AD=A3=E5=9C=A8=E4=BD=BF=E7=94=A8=E7=9A=84=E5=8A=A8=E6=80=81?= - =?UTF-8?q?=E5=9B=BE=E9=9B=86=E5=8C=BA=E5=9F=9F=E8=A2=AB=E9=94=80=E6=AF=81?= - =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - ---- - engine/cocos2d/core/components/CCLabel.js | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/engine/cocos2d/core/components/CCLabel.js b/engine/cocos2d/core/components/CCLabel.js -index 6cbfe1b..9d22219 100644 ---- a/engine/cocos2d/core/components/CCLabel.js -+++ b/engine/cocos2d/core/components/CCLabel.js -@@ -478,7 +478,7 @@ let Label = cc.Class({ - if (this.cacheMode === oldValue) return; - - if (oldValue === CacheMode.BITMAP && !(this.font instanceof cc.BitmapFont)) { -- this._frame && this._frame._resetDynamicAtlasFrame(); -+ deleteFromDynamicAtlas(this, this._frame); - } - - if (oldValue === CacheMode.CHAR) { -@@ -665,9 +665,12 @@ let Label = cc.Class({ - this._assemblerData = null; - this._letterTexture = null; - if (this._ttfTexture) { -+ // HACK 由于会出现多个 uuid 一样的情况,销毁时会将动态图集中的区域直接销毁,导致其它使用该区域的 Label 显示错误,所以先将 packable = false,不走销毁逻辑,在下方走 frame 的回收逻辑 -+ this._ttfTexture._packable = false; - this._ttfTexture.destroy(); - this._ttfTexture = null; - } -+ this._resetFrame(); - this._super(); - }, - -@@ -784,7 +787,7 @@ let Label = cc.Class({ - } - - if (this.cacheMode !== CacheMode.CHAR) { -- this._frame._resetDynamicAtlasFrame(); -+ deleteFromDynamicAtlas(this, this._frame); - this._frame._refreshTexture(this._ttfTexture); - if (this._srcBlendFactor === cc.macro.BlendFactor.ONE && !CC_NATIVERENDERER) { - this._ttfTexture.setPremultiplyAlpha(true); --- -2.32.0 (Apple Git-132) - diff --git a/patches/v1.0.0/0016-Spine-assembler.patch b/patches/v1.0.0/0016-Spine-assembler.patch deleted file mode 100644 index 53321841..00000000 --- a/patches/v1.0.0/0016-Spine-assembler.patch +++ /dev/null @@ -1,39 +0,0 @@ -From fcca26d142f2ccab5330dc079fad45aa3f92fec9 Mon Sep 17 00:00:00 2001 -From: SmallMain -Date: Wed, 22 Jun 2022 00:54:12 +0800 -Subject: [PATCH 16/16] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20Spine=20=E6=B2=A1?= - =?UTF-8?q?=E6=9C=89=20assembler=20=E6=97=B6=E6=8A=A5=E9=94=99=E7=9A=84?= - =?UTF-8?q?=E9=97=AE=E9=A2=98?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - ---- - engine/extensions/spine/Skeleton.js | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/engine/extensions/spine/Skeleton.js b/engine/extensions/spine/Skeleton.js -index b1eda9c..49a7605 100644 ---- a/engine/extensions/spine/Skeleton.js -+++ b/engine/extensions/spine/Skeleton.js -@@ -702,7 +702,7 @@ sp.Skeleton = cc.Class({ - - if (this.isAnimationCached()) { - -- this._assembler.handleDynamicAtlasAndSwitchMaterial(this); -+ if (this._assembler) this._assembler.handleDynamicAtlasAndSwitchMaterial(this); - - // Cache mode and has animation queue. - if (this._isAniComplete) { -@@ -1088,7 +1088,7 @@ sp.Skeleton = cc.Class({ - if (this.attachUtil._hasAttachedNode()) { - this._frameCache.enableCacheAttachedInfo(); - } -- this._assembler.handleDynamicAtlasAndSwitchMaterial(this); -+ if (this._assembler) this._assembler.handleDynamicAtlasAndSwitchMaterial(this); - this._frameCache.updateToFrame(0); - this._curFrame = this._frameCache.frames[0]; - } --- -2.32.0 (Apple Git-132) -