CCCExtend.ts 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /**
  2. * 重写引擎方法,进行一些功能扩展
  3. */
  4. const { ccclass } = cc._decorator;
  5. @ccclass
  6. export default class LevelExtend extends cc.Component{
  7. protected onLoad(): void {
  8. CCCExtend.init();
  9. }
  10. }
  11. class CCCExtend {
  12. /** 初始化扩展 */
  13. static init() {
  14. this._extendRenderFlow();
  15. }
  16. /** 扩展渲染流,新增层级渲染 */
  17. private static _extendRenderFlow() {
  18. let FlagOfset = 0;
  19. const DONOTHING = 1 << FlagOfset++;
  20. const BREAK_FLOW = 1 << FlagOfset++;
  21. const LOCAL_TRANSFORM = 1 << FlagOfset++;
  22. const WORLD_TRANSFORM = 1 << FlagOfset++;
  23. const TRANSFORM = LOCAL_TRANSFORM | WORLD_TRANSFORM;
  24. const UPDATE_RENDER_DATA = 1 << FlagOfset++;
  25. const OPACITY = 1 << FlagOfset++;
  26. const COLOR = 1 << FlagOfset++;
  27. const OPACITY_COLOR = OPACITY | COLOR;
  28. const RENDER = 1 << FlagOfset++;
  29. const CHILDREN = 1 << FlagOfset++;
  30. const POST_RENDER = 1 << FlagOfset++;
  31. const FINAL = 1 << FlagOfset++;
  32. const renderFlow = cc["RenderFlow"];
  33. const _batcher = renderFlow.getBachther();
  34. let __levelBatcher: { worldMatDirty: number, parentOpacityDirty }[] = [];
  35. let __renderQueue: cc.Node[][] = [];
  36. Object.defineProperty(renderFlow.prototype, "_opacity", {
  37. value: function (node) {
  38. _batcher.parentOpacityDirty++;
  39. if (node["__levelRender"] && __levelBatcher[node["__itemIndex"]]) {
  40. __levelBatcher[node["__itemIndex"]].parentOpacityDirty = 1;
  41. }
  42. this._next._func(node);
  43. node._renderFlag &= ~OPACITY;
  44. if (node["__levelRender"] && __levelBatcher[node["__itemIndex"]] && node["__lastChildren"]) {
  45. __levelBatcher[node.__itemIndex].parentOpacityDirty = 0;
  46. }
  47. _batcher.parentOpacityDirty--;
  48. }
  49. })
  50. Object.defineProperty(renderFlow.prototype, "_worldTransform", {
  51. value: function (node) {
  52. _batcher.worldMatDirty++;
  53. if (node["__levelRender"] && __levelBatcher[node["__itemIndex"]]) {
  54. __levelBatcher[node["__itemIndex"]].worldMatDirty = 1;
  55. }
  56. let t = node._matrix;
  57. let trs = node._trs;
  58. let tm = t.m;
  59. tm[12] = trs[0];
  60. tm[13] = trs[1];
  61. tm[14] = trs[2];
  62. node._mulMat(node._worldMatrix, node._parent._worldMatrix, t);
  63. node._renderFlag &= ~WORLD_TRANSFORM;
  64. this._next._func(node);
  65. if (node["__levelRender"] && __levelBatcher[node["__itemIndex"]] && node["__lastChildren"]) {
  66. __levelBatcher[node.__itemIndex].worldMatDirty = 0;
  67. }
  68. _batcher.worldMatDirty--;
  69. }
  70. });
  71. const levelSplit = (node: cc.Node, lv: number, itemIndex) => {
  72. if (!__renderQueue[lv]) {
  73. __renderQueue[lv] = [];
  74. }
  75. __renderQueue[lv].push(node);
  76. lv++;
  77. node["__renderLv"] = lv;
  78. node["__levelRender"] = true;
  79. node["__itemIndex"] = itemIndex;
  80. const cs = node.children;
  81. for (let i = 0; i < cs.length; ++i) {
  82. const c = cs[i];
  83. if (!__renderQueue[lv]) {
  84. __renderQueue[lv] = [];
  85. }
  86. lv = levelSplit(c, lv, itemIndex);
  87. }
  88. return lv;
  89. }
  90. const checkLevelRender = (levelRenderNode: cc.Node) => {
  91. const cs = levelRenderNode.children;
  92. let rootOpacityInHierarchy = levelRenderNode["opacity"] / 255;
  93. __levelBatcher = [];
  94. for (let i = 0; i < cs.length; ++i) {
  95. __levelBatcher.push({ worldMatDirty: 0, parentOpacityDirty: 0 });
  96. levelSplit(cs[i], 0, i);
  97. }
  98. while (__renderQueue.length > 0) {
  99. const list = __renderQueue.shift();
  100. if (list.length > 0) {
  101. while (list.length > 0) {
  102. const n = list.shift();
  103. n["__lastChildren"] = __renderQueue.length == 0;
  104. n["__levelRender"] = true;
  105. let opacityInHierarchy = n.parent["__opacityInHierarchy"];
  106. if (opacityInHierarchy === undefined) {
  107. opacityInHierarchy = rootOpacityInHierarchy;
  108. }
  109. let opacity = (opacityInHierarchy * (n["_opacity"] / 255));
  110. n["__opacityInHierarchy"] = opacity;
  111. let cullingMask = n["_cullingMask"];
  112. let worldMatDirty = 0;
  113. if (__levelBatcher[n["__itemIndex"]]) {
  114. worldMatDirty = __levelBatcher[n["__itemIndex"]].worldMatDirty || 0;
  115. }
  116. let parentOpacityDirty = 0;
  117. if (__levelBatcher[n["__itemIndex"]]) {
  118. parentOpacityDirty = __levelBatcher[n["__itemIndex"]].parentOpacityDirty || 0;
  119. }
  120. let worldTransformFlag = (worldMatDirty || _batcher.worldMatDirty) ? WORLD_TRANSFORM : 0;
  121. let worldOpacityFlag = (parentOpacityDirty || _batcher.parentOpacityDirty) ? OPACITY_COLOR : 0;
  122. let worldDirtyFlag = worldTransformFlag | worldOpacityFlag;
  123. n["_renderFlag"] |= worldDirtyFlag;
  124. if (!n["_activeInHierarchy"]) continue;
  125. n["_cullingMask"] = n.groupIndex === 0 ? cullingMask : 1 << n.groupIndex;
  126. // TODO: Maybe has better way to implement cascade opacity
  127. let colorVal = n["_color"]._val;
  128. n["_color"]._fastSetA(n["_opacity"] * opacity);
  129. renderFlow.flows[n["_renderFlag"]]._func(n);
  130. n["_color"]._val = colorVal;
  131. }
  132. }
  133. }
  134. }
  135. Object.defineProperty(renderFlow.prototype, "_children", {
  136. value: function (node) {
  137. if (node.__levelRender) return;
  138. let cullingMask = node._cullingMask;
  139. let enableLevelRender = node["__enableLevelRender"];
  140. const parentOpacityInHierarchy = node.parent ? node.parent["__opacityInHierarchy"] : undefined;
  141. let parentOpacity = parentOpacityInHierarchy !== undefined ? parentOpacityInHierarchy : _batcher.parentOpacity;
  142. if (!enableLevelRender && !node.__levelRender) {
  143. let opacity = (parentOpacity *= (node._opacity / 255));
  144. node["__opacityInHierarchy"] = opacity;
  145. let worldTransformFlag = _batcher.worldMatDirty ? WORLD_TRANSFORM : 0;
  146. let worldOpacityFlag = _batcher.parentOpacityDirty ? OPACITY_COLOR : 0;
  147. let worldDirtyFlag = worldTransformFlag | worldOpacityFlag;
  148. let children = node._children;
  149. for (let i = 0, l = children.length; i < l; i++) {
  150. let c = children[i];
  151. // Advance the modification of the flag to avoid node attribute modification is invalid when opacity === 0.
  152. c._renderFlag |= worldDirtyFlag;
  153. c["__opacityInHierarchy"] = c._opacity * opacity / 255;
  154. if (!c._activeInHierarchy || c._opacity === 0) continue;
  155. c._cullingMask = c.groupIndex === 0 ? cullingMask : 1 << c.groupIndex;
  156. // TODO: Maybe has better way to implement cascade opacity
  157. let colorVal = c._color._val;
  158. c._color._fastSetA(c._opacity * opacity);
  159. renderFlow.flows[c._renderFlag]._func(c)
  160. c._color._val = colorVal;
  161. }
  162. } else {
  163. checkLevelRender(node);
  164. }
  165. _batcher.parentOpacity = parentOpacity;
  166. this._next._func(node);
  167. }
  168. })
  169. }
  170. }