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

569 lines
15 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

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

From 6816546edb39321714e08ad5332995dfabdc6f03 Mon Sep 17 00:00:00 2001
From: SmallMain <smallmain@outlook.com>
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)