import { getMaterialHash } from "./MultUtils"; const _textrue = { texture: null, defalut: new cc.Texture2D(), getImpl: function () { return this.texture; }, }; //@ts-ignore cc.gfx.Texture2D.prototype.texID = -1; //多纹理缓存 let _cachdUseCount: number = 0; let _isMultTexture: boolean = false; let _cacheMaterials: Array = []; export const MultBatch2D: any = { enable: false, parent: null, curID: 0, incID: 0, count: 0, hash: 0, reset: function () { if(this.count > 0)this.curID++; this.incID += this.count; this.count = 0; }, clear: function () { let materials = _cacheMaterials; for (let i = 0; i < materials.length; i++) { let m: any = materials[i]; m.destroy(); m.decRef(); } _cacheMaterials.length = 0; } }; //提前加载多纹理材质 const loadMultTextures = function () { MultBatch2D.enable = false; //@ts-ignore cc.resources.load("multTextures/Mult-material", cc.Material, (err, material) => { if (!err) { //@ts-ignore let cacheMat = cc.Material.getBuiltinMaterial("2d-sprite");; if (cacheMat) { //@ts-ignore MultBatch2D.hash = getMaterialHash(cacheMat); MultBatch2D.parent = material; MultBatch2D.enable = true; material.addRef(); } } }); } //使用多纹理材质缓存 export const getMultMaterial = function (oldMat: any) { MultBatch2D.reset(); _isMultTexture = false; if (!MultBatch2D.enable || !oldMat || !oldMat.isMultTextures) { return oldMat; } if (!MultBatch2D.parent || !MultBatch2D.parent.isValid) { loadMultTextures(); return oldMat; } let newMat: any = _cacheMaterials[_cachdUseCount++]; if (!newMat || !newMat.isValid) { let MaterialVariant: any = cc.MaterialVariant; newMat = new MaterialVariant(MultBatch2D.parent); _cacheMaterials[_cachdUseCount - 1] = (newMat); for (let i = 0; i < 8; i++) { newMat.setProperty("texture" + i, _textrue.defalut); } newMat.updateHash(MultBatch2D.hash); newMat.define("USE_TEXTURE", true); newMat['isMultTextures'] = true; newMat['cacheTextures'] = [-1]; newMat.addRef(); } _isMultTexture = true; return newMat; } const fillRenderDataTexID = function (cmp: any, texID: number) { let renderData = cmp._assembler._renderData; if (!renderData) return false; let uvX = 0; let vbuf = renderData.vDatas[0]; if (cmp.dataDirty) { cmp.dataDirty = false; for (let i = 0, length = vbuf.length; i < length; i += 5) { uvX = ~~(vbuf[i + 2] * 100000); vbuf[i + 2] = uvX * 10 + texID; } } else { if (cmp.texID != texID) { for (let i = 0, length = vbuf.length; i < length; i += 5) { uvX = ~~(vbuf[i + 2] * 0.1); vbuf[i + 2] = uvX * 10 + texID; } } } cmp.texID = texID; } const bindMultTexture = function (cmp: cc.RenderComponent, material: cc.Material, renderer: any) { if (!_isMultTexture || !material) return; //@ts-ignore let texture: any = material.effect.passes[0].getProperty("texture"); if (!texture) return; //_textrue.defalut; // const MB = MultBatch2D; //@ts-ignore let effect = material.effect; let id = texture.texID - MB.incID; if (id < 0) { if (MB.count >= 8) { if (!CC_JSB) renderer._flush(); renderer.material = getMultMaterial(material); renderer.node = material.getDefine("CC_USE_MODEL") ? cmp.node : renderer._dummyNode; } id = MB.count++; texture.texID = id + MB.incID; //绑定上传纹理->多纹理材质 let curMaterial = renderer.material; let cache = curMaterial['cacheTextures']; if (cache[id] !== texture._id) { cache[id] = texture._id; _textrue.texture = texture; curMaterial.setProperty("texture" + id, _textrue); curMaterial.effect._dirty = false; curMaterial._dirty = false; } if (id == 0 && CC_JSB) { let obj = curMaterial._effect._nativeObj; if (material['_obj'] !== obj) { material['_obj'] = obj; effect._nativeObj.setEffect(obj); } } } if (CC_JSB) { let hash = MB.curID + 0.5; if (material['_hash'] !== hash) { material['_hash'] = hash; effect._nativeObj.updateHash(hash); } } //记录上传纹理id->顶点数据 fillRenderDataTexID(cmp, id); } if (!CC_EDITOR) {//&& !CC_JSB const RenderCmp: any = cc.RenderComponent.prototype; RenderCmp.texID = -1; RenderCmp.vDitry = true; RenderCmp.dataDirty = true; //顶点数据更改检测 Object.defineProperty(RenderCmp, "_vertsDirty", { get: function () { return this.vDitry; }, set: function (flag) { if (!flag && this.vDitry) { this.dataDirty = true; } this.vDitry = flag; }, }); //材质切换检测 const setMaterial = RenderCmp.setMaterial; RenderCmp.setMaterial = function (index, material) { let isMultTextures = false; let oldMat = this._materials[index]; if (oldMat) { isMultTextures = oldMat.isMultTextures; } let newMat = setMaterial.call(this, index, material); this.setVertsDirty(); //isMultTextures && return newMat; } //多纹理材质hash检测 const Material: any = cc.Material.prototype; const getHash = Material.getHash; Material.getHash = function () { let effect: any = this._effect; if (MultBatch2D.enable && effect && effect._dirty) { this['isMultTextures'] = false; let uir = this._owner; if (uir && (uir instanceof cc.Sprite || uir instanceof cc.Label)) { let hash = getMaterialHash(this); if (hash == MultBatch2D.hash) { this['isMultTextures'] = true; effect._dirty = false; effect._hash = hash; return hash; } } } return getHash.call(this); } //重写 _checkBacth 合批分发函数 RenderCmp._checkBacth = function (renderer, cullingMask) { let material: any = this._materials[0]; if ((material && material.getHash() !== renderer.material.getHash()) || renderer.cullingMask !== cullingMask) { if (!CC_JSB) renderer._flush(); renderer.node = material.getDefine("CC_USE_MODEL") ? this.node : renderer._dummyNode; renderer.material = getMultMaterial(material); renderer.cullingMask = cullingMask; } bindMultTexture(this, material, renderer); }; cc.game.on(cc.game.EVENT_GAME_INITED, () => { loadMultTextures(); }); cc.game.on(cc.game.EVENT_ENGINE_INITED, () => { }); cc.director.on(cc.Director.EVENT_BEFORE_DRAW, () => { _cachdUseCount = 0; MultBatch2D.reset(); MultBatch2D.curID = 0; }); }