mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2024-12-26 11:48:29 +00:00
569 lines
15 KiB
Diff
569 lines
15 KiB
Diff
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)
|
||
|