material.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. 'use strict';
  2. /**
  3. * Pass the data of a pass under a technique and organize it into a tree structure
  4. * @param passData
  5. */
  6. exports.buildEffect = function(index, passData) {
  7. const props = passData.props;
  8. const defs = passData.defines;
  9. const tree = {
  10. name: `Pass ${index}${passData.phase ? ' - ' + passData.phase : ''}`,
  11. type: 'cc.Object',
  12. childMap: {},
  13. };
  14. const hideAttrs = ['USE_INSTANCING'];
  15. function encode(item) {
  16. let current = tree;
  17. /**
  18. * USE_INSTANCING is common to every child in passes
  19. * To make editing easier, they are referred to the outside of the passes
  20. * At this point, you need to set each of the passes to be non-editable and invisible
  21. */
  22. if (hideAttrs.includes(item.name)) {
  23. item.visible = false;
  24. }
  25. if (item.defines && item.defines.length) {
  26. item.defines.forEach((name) => {
  27. // The defines starting with ! are reverse dependencies, the data position will not change
  28. if (name.startsWith('!')) {
  29. return;
  30. }
  31. let child = current.childMap[name];
  32. if (!child) {
  33. child = current.childMap[name] = {
  34. name,
  35. // type: 'ui.Depend',
  36. type: 'Boolean',
  37. childMap: {},
  38. };
  39. }
  40. current = child;
  41. });
  42. }
  43. if (current.childMap[item.name]) {
  44. const tempChildMap = current.childMap[item.name].childMap;
  45. current.childMap[item.name] = item;
  46. item.childMap = tempChildMap;
  47. } else {
  48. current.childMap[item.name] = item;
  49. item.childMap = {};
  50. }
  51. current.childMap[item.name].name = item.name;
  52. }
  53. defs.forEach((item) => {
  54. switch (item.type) {
  55. case 'Number':
  56. item.type = 'Enum';
  57. item.enumList = [];
  58. for (let i = item.range[0]; i <= item.range[1]; i++) {
  59. item.enumList.push({
  60. name: i,
  61. value: i,
  62. });
  63. }
  64. break;
  65. case 'String':
  66. item.type = 'Enum';
  67. item.enumList = item.options.map((str) => {
  68. return {
  69. name: str,
  70. value: str,
  71. };
  72. });
  73. break;
  74. case 'Enum': break; // Fix the problem that item.type === 'Enum' is reset to 'ui.Depend'
  75. default:
  76. // item.type = 'ui.Depend';
  77. item.type = 'Boolean';
  78. }
  79. encode(item);
  80. });
  81. props.forEach(encode);
  82. function encodeStates(item) {
  83. let current = tree;
  84. if (current.childMap[item.name]) {
  85. const tempChildMap = current.childMap[item.name].childMap;
  86. current.childMap[item.name] = item;
  87. item.childMap = tempChildMap;
  88. } else {
  89. current.childMap[item.name] = item;
  90. item.childMap = {};
  91. }
  92. if (item.isObject && item.value) {
  93. current = current.childMap[item.name];
  94. Object.keys(item.value).forEach((name) => {
  95. let child = current.childMap[name];
  96. if (!child) {
  97. child = current.childMap[name] = {
  98. name,
  99. type: 'cc.Object',
  100. childMap: {},
  101. };
  102. }
  103. });
  104. }
  105. }
  106. function modifyType(item) {
  107. if (!item) {
  108. return;
  109. }
  110. if (item.isObject) {
  111. Object.keys(item.value).forEach((key) => {
  112. modifyType(item.value[key]);
  113. });
  114. } else if (item.isArray) {
  115. item.value.forEach((data) => {
  116. modifyType(data);
  117. });
  118. modifyType(item.elementTypeData);
  119. } else {
  120. switch (item.type) {
  121. case 'Number':
  122. if (item.isEnum) {
  123. item.type = 'Enum';
  124. item.enumList = [];
  125. Object.keys(item.enumData).forEach((key) => {
  126. item.enumList.push({
  127. name: key,
  128. value: item.enumData[key],
  129. });
  130. });
  131. }
  132. break;
  133. }
  134. }
  135. }
  136. modifyType(passData.states);
  137. encodeStates(passData.states);
  138. function translate(item) {
  139. const children = Object.keys(item.childMap).map((name) => {
  140. const child = item.childMap[name];
  141. translate(child);
  142. return child;
  143. });
  144. if (item) {
  145. item.children = children;
  146. }
  147. return item;
  148. }
  149. const dump = translate(tree);
  150. dump.value = tree.childMap;
  151. return dump;
  152. };
  153. exports.materialTechniquePolyfill = function(origin) {
  154. let useInstancing;
  155. const passes = origin.passes.map((data, index) => {
  156. // Merge data.defines and data.props
  157. const pass = exports.buildEffect(index, data);
  158. pass.switch = data.switch;
  159. pass.propertyIndex = data.propertyIndex;
  160. if (!useInstancing && pass.childMap.USE_INSTANCING) {
  161. useInstancing = JSON.parse(JSON.stringify(pass.childMap.USE_INSTANCING));
  162. useInstancing.visible = true;
  163. }
  164. return pass;
  165. });
  166. /**
  167. * USE_INSTANCING is common to every child in passes
  168. * For ease of editing, they are referred to outside of the passes
  169. * Two external variables useInstancing, useBatching are provided to dock
  170. * The value of the first pass takes precedence
  171. */
  172. const technique = {
  173. name: origin.name,
  174. passes,
  175. useInstancing,
  176. };
  177. return technique;
  178. };