Files
heros/assets/resources/multTextures/MultTextures.ts
2024-08-03 23:54:37 +08:00

307 lines
9.7 KiB
TypeScript

//*//
import { BaseRenderData, Director, Game, Material, Node, ParticleSystem2D, Sprite, SpriteFrame, StencilManager, UIRenderer, __private, _decorator, assert, cclegacy, director, game, renderer, resources } from 'cc';
import { DEBUG, EDITOR, JSB } from 'cc/env';
const { ccclass, property } = _decorator;
export const MultBatch2D: any = {
enable: false,
parent: null,
textures: [],
hash: 0,
reset: function () {
this.textures.length = 0;
}
};
let _cacheUseCount: number = 0;
let _cacheMaterials: Array<Material> = [];
const getMultMaterial = function () {
if (!MultBatch2D.enable) return null;
let material: any = _cacheMaterials[_cacheUseCount++];
if (!material) {
const mat = { parent: MultBatch2D.parent };
material = new renderer.MaterialInstance(mat);
material['isMultTextures'] = true;
_cacheMaterials.push(material);
}
return material;
}
let MAX_TEX = 8;
const _texture = {
texture: new cclegacy.SimpleTexture(),
defalut: new cclegacy.SimpleTexture(),
setFrame(frame: any) {
this.texture['_gfxSampler'] = frame.getGFXSampler();
this.texture['_gfxTextureView'] = frame.getGFXTexture();
}
};
game.once(Game.EVENT_GAME_INITED, () => {
if (EDITOR || JSB) return;
resources.load("multTextures/Mult-material", Material, (err, material) => {
if (!err) {
let mat = cclegacy.builtinResMgr.get('ui-sprite-material');
MultBatch2D.hash = Material.getHash(mat);
MultBatch2D.parent = material;
MultBatch2D.enable = true;
}
});
const UIR: any = UIRenderer.prototype;
const updateMaterial: any = UIR.updateMaterial;
UIR.updateMaterial = function () {
updateMaterial.call(this);
//this.getSharedMaterial(0);
let material = this.customMaterial || this.material;
if (material) {
material['isMultTextures'] = false;
if (MultBatch2D.hash == material.hash) {
material['isMultTextures'] = true;
}
}
}
const PS2D: any = ParticleSystem2D.prototype;
const _updateMaterial = PS2D._updateMaterial;
PS2D._updateMaterial = function () {
_updateMaterial.call(this);
let material = this.customMaterial || this.material;
if (material) {
material['isMultTextures'] = false;
if (MultBatch2D.hash == material.hash) {
material['isMultTextures'] = true;
}
}
}
});
game.once(Game.EVENT_ENGINE_INITED, () => {
if (EDITOR || JSB) return;
cclegacy.UI.RenderData.prototype.texID = -1;
cclegacy.UI.RenderData.prototype.texDirty = true;
cclegacy.UI.RenderData.prototype.dataDirty = true;
Object.defineProperty(cclegacy.UI.RenderData.prototype, "vertDirty", {
get: function () {
return this._vertDirty;
},
set: function (val: boolean) {
this._vertDirty = val;
if (val === true) {
this.dataDirty = true;
}
if (this._renderDrawInfo && val) {
this._renderDrawInfo.setVertDirty(val);
}
}
});
Object.defineProperty(cclegacy.UI.RenderData.prototype, "textureDirty", {
get: function () {
return this.texDirty;
},
set: function (val: boolean) {
this.texDirty = val;
if (val === true) {
this.texID = -1;
}
}
});
const Spr: any = Sprite.prototype;
Spr.flagChangedVersion = -1;
Object.defineProperty(Spr, "_flagChangedVersion", {
get: function () {
return this.flagChangedVersion;
},
set: function (val: number) {
if (this.flagChangedVersion != val) {
this.flagChangedVersion = val;
let rd = this.renderData;
let type = this.type;
if (rd && type == Sprite.Type.TILED
|| (type == Sprite.Type.FILLED && Sprite.FillType.RADIAL)) {
rd.dataDirty = true;
}
}
}
});
director.on(Director.EVENT_AFTER_DRAW, (dt) => {
cclegacy.internal.Batcher2D._rdHash = -1;
MultBatch2D.reset();
_cacheUseCount = 0;
});
cclegacy.internal.Batcher2D.prototype.currMaterial = null;
Object.defineProperty(cclegacy.internal.Batcher2D.prototype, "_currMaterial", {
get: function () {
return this.currMaterial;
},
set: function (metrial: any) {
if (this.currMaterial === metrial) return;
this.currMaterial = metrial;
MultBatch2D.reset();
if (metrial && metrial.isMultTextures) {
let mat = getMultMaterial();
if (mat) {
this.currMaterial = mat;
}
}
}
});
const Stage_ENTER_LEVEL = 2;
const Stage_ENTER_LEVEL_INVERTED = 6;
type TextureBase = __private._cocos_asset_assets_texture_base__TextureBase;
cclegacy.internal.Batcher2D.prototype._rdHash = -1;
cclegacy.internal.Batcher2D.prototype.commitComp = function (comp: UIRenderer, renderData: BaseRenderData | null, frame: TextureBase | SpriteFrame | null, assembler: any, transform: Node | null) {
let rdHash = -1;
let dataHash = 0;
let mat: any;
let bufferID = -1;
if (renderData && renderData.chunk) {
if (!renderData.isValid()) return;
dataHash = renderData.dataHash;
mat = renderData.material;
bufferID = renderData.chunk.bufferId;
// as RenderData;
let rd: any = renderData;
rdHash = bufferID << 16 | rd.layer;
}
// Notice: A little hack, if it is for mask, not need update here, while control by stencilManger
if (comp.stencilStage === Stage_ENTER_LEVEL || comp.stencilStage === Stage_ENTER_LEVEL_INVERTED) {
this._insertMaskBatch(comp);
} else {
comp.stencilStage = StencilManager.sharedManager!.stage;
}
const depthStencilStateStage = comp.stencilStage;
let texID = -1;
let texture = null;
let flushBatch = false;
let isMultTextures = false;
if (MultBatch2D.enable && mat && mat.isMultTextures) {
texture = frame && frame.getGFXTexture();
texID = MultBatch2D.textures.indexOf(texture);
isMultTextures = true;
if (texID < 0) {
if (MultBatch2D.textures.length == MAX_TEX) {
// MultBatch2D.textures.length = 0;
flushBatch = true;
}
}
if (this._currMaterial && this._currMaterial.isMultTextures) {
mat = this._currMaterial;
dataHash = this._currHash;
if (this._rdHash != rdHash) {
flushBatch = true;
texID = -1;
}
}
}
if (flushBatch
|| this._currHash !== dataHash || dataHash === 0 || this._currMaterial !== mat
|| this._currDepthStencilStateStage !== depthStencilStateStage) {
// Merge all previous data to a render batch, and update buffer for next render data
this.autoMergeBatches(this._currComponent!);
if (renderData && !renderData._isMeshBuffer) {
this.updateBuffer(renderData.vertexFormat, bufferID);
}
this._rdHash = rdHash;
this._currRenderData = renderData;
this._currHash = renderData ? renderData.dataHash : 0;
this._currComponent = comp;
this._currTransform = transform;
this._currMaterial = comp.getRenderMaterial(0)!;
this._currDepthStencilStateStage = depthStencilStateStage;
this._currLayer = comp.node.layer;
if (frame) {
if (DEBUG) {
assert(frame.isValid, 'frame should not be invalid, it may have been released');
}
this._currTexture = frame.getGFXTexture();
this._currSampler = frame.getGFXSampler();
this._currTextureHash = frame.getHash();
this._currSamplerHash = this._currSampler.hash;
} else {
this._currTexture = null;
this._currSampler = null;
this._currTextureHash = 0;
this._currSamplerHash = 0;
}
}
assembler.fillBuffers(comp, this);
if (isMultTextures) {
if (texID < 0) {
texID = MultBatch2D.textures.length;
MultBatch2D.textures.push(texture);
if (texID > 0) {
_texture.setFrame(frame);
const name = "texture" + texID;
this._currMaterial.setProperty(name, _texture.texture);
}
}
this._fillDatas(renderData, texID);
}
}
cclegacy.internal.Batcher2D.prototype["_fillDatas"] = function (renderData: any, texID: number) {
if (!renderData) return;
let uvX = 0;
let vbuf = renderData.chunk.vb;
if (renderData.dataDirty) {
renderData.dataDirty = false;
for (let i = 0, length = vbuf.length; i < length; i += 9) {
uvX = ~~(vbuf[i + 3] * 100000);
vbuf[i + 3] = uvX * 10 + texID;
}
} else {
if (renderData.texID != texID) {
for (let i = 0, length = vbuf.length; i < length; i += 9) {
uvX = ~~(vbuf[i + 3] * 0.1);
vbuf[i + 3] = uvX * 10 + texID;
}
}
}
renderData.texID = texID;
};
});
//*/