MultTextures.ts 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. import { getMaterialHash } from "./MultUtils";
  2. const _textrue = {
  3. texture: null,
  4. defalut: new cc.Texture2D(),
  5. getImpl: function () {
  6. return this.texture;
  7. },
  8. };
  9. //@ts-ignore
  10. cc.gfx.Texture2D.prototype.texID = -1;
  11. //多纹理缓存
  12. let _cachdUseCount: number = 0;
  13. let _isMultTexture: boolean = false;
  14. let _cacheMaterials: Array<cc.Material> = [];
  15. export const MultBatch2D: any = {
  16. enable: false,
  17. parent: null,
  18. curID: 0,
  19. incID: 0,
  20. count: 0,
  21. hash: 0,
  22. reset: function () {
  23. if(this.count > 0)this.curID++;
  24. this.incID += this.count;
  25. this.count = 0;
  26. },
  27. clear: function () {
  28. let materials = _cacheMaterials;
  29. for (let i = 0; i < materials.length; i++) {
  30. let m: any = materials[i];
  31. m.destroy();
  32. m.decRef();
  33. }
  34. _cacheMaterials.length = 0;
  35. }
  36. };
  37. //提前加载多纹理材质
  38. const loadMultTextures = function () {
  39. MultBatch2D.enable = false;
  40. //@ts-ignore
  41. cc.resources.load("multTextures/Mult-material", cc.Material, (err, material) => {
  42. if (!err) {
  43. //@ts-ignore
  44. let cacheMat = cc.Material.getBuiltinMaterial("2d-sprite");;
  45. if (cacheMat) {
  46. //@ts-ignore
  47. MultBatch2D.hash = getMaterialHash(cacheMat);
  48. MultBatch2D.parent = material;
  49. MultBatch2D.enable = true;
  50. material.addRef();
  51. }
  52. }
  53. });
  54. }
  55. //使用多纹理材质缓存
  56. export const getMultMaterial = function (oldMat: any) {
  57. MultBatch2D.reset();
  58. _isMultTexture = false;
  59. if (!MultBatch2D.enable ||
  60. !oldMat || !oldMat.isMultTextures) {
  61. return oldMat;
  62. }
  63. if (!MultBatch2D.parent
  64. || !MultBatch2D.parent.isValid) {
  65. loadMultTextures();
  66. return oldMat;
  67. }
  68. let newMat: any = _cacheMaterials[_cachdUseCount++];
  69. if (!newMat || !newMat.isValid) {
  70. let MaterialVariant: any = cc.MaterialVariant;
  71. newMat = new MaterialVariant(MultBatch2D.parent);
  72. _cacheMaterials[_cachdUseCount - 1] = (newMat);
  73. for (let i = 0; i < 8; i++) {
  74. newMat.setProperty("texture" + i, _textrue.defalut);
  75. }
  76. newMat.updateHash(MultBatch2D.hash);
  77. newMat.define("USE_TEXTURE", true);
  78. newMat['isMultTextures'] = true;
  79. newMat['cacheTextures'] = [-1];
  80. newMat.addRef();
  81. }
  82. _isMultTexture = true;
  83. return newMat;
  84. }
  85. const fillRenderDataTexID = function (cmp: any, texID: number) {
  86. let renderData = cmp._assembler._renderData;
  87. if (!renderData) return false;
  88. let uvX = 0;
  89. let vbuf = renderData.vDatas[0];
  90. if (cmp.dataDirty) {
  91. cmp.dataDirty = false;
  92. for (let i = 0, length = vbuf.length; i < length; i += 5) {
  93. uvX = ~~(vbuf[i + 2] * 100000);
  94. vbuf[i + 2] = uvX * 10 + texID;
  95. }
  96. } else {
  97. if (cmp.texID != texID) {
  98. for (let i = 0, length = vbuf.length; i < length; i += 5) {
  99. uvX = ~~(vbuf[i + 2] * 0.1);
  100. vbuf[i + 2] = uvX * 10 + texID;
  101. }
  102. }
  103. }
  104. cmp.texID = texID;
  105. }
  106. const bindMultTexture = function (cmp: cc.RenderComponent, material: cc.Material, renderer: any) {
  107. if (!_isMultTexture || !material) return;
  108. //@ts-ignore
  109. let texture: any = material.effect.passes[0].getProperty("texture");
  110. if (!texture) return; //_textrue.defalut; //
  111. const MB = MultBatch2D;
  112. //@ts-ignore
  113. let effect = material.effect;
  114. let id = texture.texID - MB.incID;
  115. if (id < 0) {
  116. if (MB.count >= 8) {
  117. if (!CC_JSB) renderer._flush();
  118. renderer.material = getMultMaterial(material);
  119. renderer.node = material.getDefine("CC_USE_MODEL") ? cmp.node : renderer._dummyNode;
  120. }
  121. id = MB.count++;
  122. texture.texID = id + MB.incID;
  123. //绑定上传纹理->多纹理材质
  124. let curMaterial = renderer.material;
  125. let cache = curMaterial['cacheTextures'];
  126. if (cache[id] !== texture._id) {
  127. cache[id] = texture._id;
  128. _textrue.texture = texture;
  129. curMaterial.setProperty("texture" + id, _textrue);
  130. curMaterial.effect._dirty = false;
  131. curMaterial._dirty = false;
  132. }
  133. if (id == 0 && CC_JSB) {
  134. let obj = curMaterial._effect._nativeObj;
  135. if (material['_obj'] !== obj) {
  136. material['_obj'] = obj;
  137. effect._nativeObj.setEffect(obj);
  138. }
  139. }
  140. }
  141. if (CC_JSB) {
  142. let hash = MB.curID + 0.5;
  143. if (material['_hash'] !== hash) {
  144. material['_hash'] = hash;
  145. effect._nativeObj.updateHash(hash);
  146. }
  147. }
  148. //记录上传纹理id->顶点数据
  149. fillRenderDataTexID(cmp, id);
  150. }
  151. if (!CC_EDITOR) {//&& !CC_JSB
  152. const RenderCmp: any = cc.RenderComponent.prototype;
  153. RenderCmp.texID = -1;
  154. RenderCmp.vDitry = true;
  155. RenderCmp.dataDirty = true;
  156. //顶点数据更改检测
  157. Object.defineProperty(RenderCmp, "_vertsDirty", {
  158. get: function () {
  159. return this.vDitry;
  160. },
  161. set: function (flag) {
  162. if (!flag && this.vDitry) {
  163. this.dataDirty = true;
  164. }
  165. this.vDitry = flag;
  166. },
  167. });
  168. //材质切换检测
  169. const setMaterial = RenderCmp.setMaterial;
  170. RenderCmp.setMaterial = function (index, material) {
  171. let isMultTextures = false;
  172. let oldMat = this._materials[index];
  173. if (oldMat) {
  174. isMultTextures = oldMat.isMultTextures;
  175. }
  176. let newMat = setMaterial.call(this, index, material);
  177. this.setVertsDirty(); //isMultTextures &&
  178. return newMat;
  179. }
  180. //多纹理材质hash检测
  181. const Material: any = cc.Material.prototype;
  182. const getHash = Material.getHash;
  183. Material.getHash = function () {
  184. let effect: any = this._effect;
  185. if (MultBatch2D.enable && effect && effect._dirty) {
  186. this['isMultTextures'] = false;
  187. let uir = this._owner;
  188. if (uir && (uir instanceof cc.Sprite || uir instanceof cc.Label)) {
  189. let hash = getMaterialHash(this);
  190. if (hash == MultBatch2D.hash) {
  191. this['isMultTextures'] = true;
  192. effect._dirty = false;
  193. effect._hash = hash;
  194. return hash;
  195. }
  196. }
  197. }
  198. return getHash.call(this);
  199. }
  200. //重写 _checkBacth 合批分发函数
  201. RenderCmp._checkBacth = function (renderer, cullingMask) {
  202. let material: any = this._materials[0];
  203. if ((material && material.getHash() !== renderer.material.getHash()) || renderer.cullingMask !== cullingMask) {
  204. if (!CC_JSB) renderer._flush();
  205. renderer.node = material.getDefine("CC_USE_MODEL") ? this.node : renderer._dummyNode;
  206. renderer.material = getMultMaterial(material);
  207. renderer.cullingMask = cullingMask;
  208. }
  209. bindMultTexture(this, material, renderer);
  210. };
  211. cc.game.on(cc.game.EVENT_GAME_INITED, () => {
  212. loadMultTextures();
  213. });
  214. cc.game.on(cc.game.EVENT_ENGINE_INITED, () => {
  215. });
  216. cc.director.on(cc.Director.EVENT_BEFORE_DRAW, () => {
  217. _cachdUseCount = 0;
  218. MultBatch2D.reset();
  219. MultBatch2D.curID = 0;
  220. });
  221. }