@onerjs/smart-filters 8.25.2 → 8.25.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/dist/IDisposable.d.ts +10 -0
  2. package/dist/IDisposable.d.ts.map +1 -0
  3. package/dist/IDisposable.js +2 -0
  4. package/dist/IDisposable.js.map +1 -0
  5. package/dist/blockFoundation/aggregateBlock.d.ts +56 -0
  6. package/dist/blockFoundation/aggregateBlock.d.ts.map +1 -0
  7. package/dist/blockFoundation/aggregateBlock.js +130 -0
  8. package/dist/blockFoundation/aggregateBlock.js.map +1 -0
  9. package/dist/blockFoundation/baseBlock.d.ts +176 -0
  10. package/dist/blockFoundation/baseBlock.d.ts.map +1 -0
  11. package/dist/blockFoundation/baseBlock.js +276 -0
  12. package/dist/blockFoundation/baseBlock.js.map +1 -0
  13. package/dist/blockFoundation/customAggregateBlock.d.ts +38 -0
  14. package/dist/blockFoundation/customAggregateBlock.d.ts.map +1 -0
  15. package/dist/blockFoundation/customAggregateBlock.js +63 -0
  16. package/dist/blockFoundation/customAggregateBlock.js.map +1 -0
  17. package/dist/blockFoundation/customShaderBlock.d.ts +73 -0
  18. package/dist/blockFoundation/customShaderBlock.d.ts.map +1 -0
  19. package/dist/blockFoundation/customShaderBlock.js +232 -0
  20. package/dist/blockFoundation/customShaderBlock.js.map +1 -0
  21. package/dist/blockFoundation/disableableShaderBlock.d.ts +56 -0
  22. package/dist/blockFoundation/disableableShaderBlock.d.ts.map +1 -0
  23. package/dist/blockFoundation/disableableShaderBlock.js +68 -0
  24. package/dist/blockFoundation/disableableShaderBlock.js.map +1 -0
  25. package/dist/blockFoundation/index.d.ts +10 -0
  26. package/dist/blockFoundation/index.d.ts.map +1 -0
  27. package/dist/blockFoundation/index.js +8 -0
  28. package/dist/blockFoundation/index.js.map +1 -0
  29. package/dist/blockFoundation/inputBlock.d.ts +127 -0
  30. package/dist/blockFoundation/inputBlock.d.ts.map +1 -0
  31. package/dist/blockFoundation/inputBlock.deserializer.d.ts +12 -0
  32. package/dist/blockFoundation/inputBlock.deserializer.d.ts.map +1 -0
  33. package/dist/blockFoundation/inputBlock.deserializer.js +65 -0
  34. package/dist/blockFoundation/inputBlock.deserializer.js.map +1 -0
  35. package/dist/blockFoundation/inputBlock.js +89 -0
  36. package/dist/blockFoundation/inputBlock.js.map +1 -0
  37. package/dist/blockFoundation/inputBlock.serialization.types.d.ts +105 -0
  38. package/dist/blockFoundation/inputBlock.serialization.types.d.ts.map +1 -0
  39. package/dist/blockFoundation/inputBlock.serialization.types.js +2 -0
  40. package/dist/blockFoundation/inputBlock.serialization.types.js.map +1 -0
  41. package/dist/blockFoundation/inputBlock.serializer.d.ts +6 -0
  42. package/dist/blockFoundation/inputBlock.serializer.d.ts.map +1 -0
  43. package/dist/blockFoundation/inputBlock.serializer.js +130 -0
  44. package/dist/blockFoundation/inputBlock.serializer.js.map +1 -0
  45. package/dist/blockFoundation/outputBlock.d.ts +47 -0
  46. package/dist/blockFoundation/outputBlock.d.ts.map +1 -0
  47. package/dist/blockFoundation/outputBlock.js +123 -0
  48. package/dist/blockFoundation/outputBlock.js.map +1 -0
  49. package/dist/blockFoundation/shaderBlock.d.ts +64 -0
  50. package/dist/blockFoundation/shaderBlock.d.ts.map +1 -0
  51. package/dist/blockFoundation/shaderBlock.js +125 -0
  52. package/dist/blockFoundation/shaderBlock.js.map +1 -0
  53. package/dist/blockFoundation/textureOptions.d.ts +47 -0
  54. package/dist/blockFoundation/textureOptions.d.ts.map +1 -0
  55. package/dist/blockFoundation/textureOptions.js +37 -0
  56. package/dist/blockFoundation/textureOptions.js.map +1 -0
  57. package/dist/command/command.d.ts +48 -0
  58. package/dist/command/command.d.ts.map +1 -0
  59. package/dist/command/command.js +15 -0
  60. package/dist/command/command.js.map +1 -0
  61. package/dist/command/commandBuffer.d.ts +40 -0
  62. package/dist/command/commandBuffer.d.ts.map +1 -0
  63. package/dist/command/commandBuffer.js +58 -0
  64. package/dist/command/commandBuffer.js.map +1 -0
  65. package/dist/command/commandBufferDebugger.d.ts +7 -0
  66. package/dist/command/commandBufferDebugger.d.ts.map +1 -0
  67. package/dist/command/commandBufferDebugger.js +13 -0
  68. package/dist/command/commandBufferDebugger.js.map +1 -0
  69. package/dist/command/index.d.ts +6 -0
  70. package/dist/command/index.d.ts.map +1 -0
  71. package/dist/command/index.js +8 -0
  72. package/dist/command/index.js.map +1 -0
  73. package/dist/connection/connectionPoint.d.ts +110 -0
  74. package/dist/connection/connectionPoint.d.ts.map +1 -0
  75. package/dist/connection/connectionPoint.js +154 -0
  76. package/dist/connection/connectionPoint.js.map +1 -0
  77. package/dist/connection/connectionPointCompatibilityState.d.ts +20 -0
  78. package/dist/connection/connectionPointCompatibilityState.d.ts.map +1 -0
  79. package/dist/connection/connectionPointCompatibilityState.js +32 -0
  80. package/dist/connection/connectionPointCompatibilityState.js.map +1 -0
  81. package/dist/connection/connectionPointDirection.d.ts +10 -0
  82. package/dist/connection/connectionPointDirection.d.ts.map +1 -0
  83. package/dist/connection/connectionPointDirection.js +11 -0
  84. package/dist/connection/connectionPointDirection.js.map +1 -0
  85. package/dist/connection/connectionPointType.d.ts +29 -0
  86. package/dist/connection/connectionPointType.d.ts.map +1 -0
  87. package/dist/connection/connectionPointType.js +19 -0
  88. package/dist/connection/connectionPointType.js.map +1 -0
  89. package/dist/connection/connectionPointWithDefault.d.ts +23 -0
  90. package/dist/connection/connectionPointWithDefault.d.ts.map +1 -0
  91. package/dist/connection/connectionPointWithDefault.js +19 -0
  92. package/dist/connection/connectionPointWithDefault.js.map +1 -0
  93. package/dist/connection/index.d.ts +8 -0
  94. package/dist/connection/index.d.ts.map +1 -0
  95. package/dist/connection/index.js +7 -0
  96. package/dist/connection/index.js.map +1 -0
  97. package/dist/editorUtils/editableInPropertyPage.d.ts +80 -0
  98. package/dist/editorUtils/editableInPropertyPage.d.ts.map +1 -0
  99. package/dist/editorUtils/editableInPropertyPage.js +42 -0
  100. package/dist/editorUtils/editableInPropertyPage.js.map +1 -0
  101. package/dist/editorUtils/index.d.ts +3 -0
  102. package/dist/editorUtils/index.d.ts.map +1 -0
  103. package/dist/editorUtils/index.js +4 -0
  104. package/dist/editorUtils/index.js.map +1 -0
  105. package/dist/index.d.ts +13 -0
  106. package/dist/index.d.ts.map +1 -0
  107. package/dist/index.js +14 -0
  108. package/dist/index.js.map +1 -0
  109. package/dist/optimization/dependencyGraph.d.ts +31 -0
  110. package/dist/optimization/dependencyGraph.d.ts.map +1 -0
  111. package/dist/optimization/dependencyGraph.js +78 -0
  112. package/dist/optimization/dependencyGraph.js.map +1 -0
  113. package/dist/optimization/index.d.ts +2 -0
  114. package/dist/optimization/index.d.ts.map +1 -0
  115. package/dist/optimization/index.js +2 -0
  116. package/dist/optimization/index.js.map +1 -0
  117. package/dist/optimization/optimizedShaderBlock.d.ts +75 -0
  118. package/dist/optimization/optimizedShaderBlock.d.ts.map +1 -0
  119. package/dist/optimization/optimizedShaderBlock.js +105 -0
  120. package/dist/optimization/optimizedShaderBlock.js.map +1 -0
  121. package/dist/optimization/smartFilterOptimizer.d.ts +126 -0
  122. package/dist/optimization/smartFilterOptimizer.d.ts.map +1 -0
  123. package/dist/optimization/smartFilterOptimizer.js +666 -0
  124. package/dist/optimization/smartFilterOptimizer.js.map +1 -0
  125. package/dist/runtime/index.d.ts +8 -0
  126. package/dist/runtime/index.d.ts.map +1 -0
  127. package/dist/runtime/index.js +7 -0
  128. package/dist/runtime/index.js.map +1 -0
  129. package/dist/runtime/renderTargetGenerator.d.ts +43 -0
  130. package/dist/runtime/renderTargetGenerator.d.ts.map +1 -0
  131. package/dist/runtime/renderTargetGenerator.js +169 -0
  132. package/dist/runtime/renderTargetGenerator.js.map +1 -0
  133. package/dist/runtime/shaderRuntime.d.ts +103 -0
  134. package/dist/runtime/shaderRuntime.d.ts.map +1 -0
  135. package/dist/runtime/shaderRuntime.js +132 -0
  136. package/dist/runtime/shaderRuntime.js.map +1 -0
  137. package/dist/runtime/smartFilterRuntime.d.ts +69 -0
  138. package/dist/runtime/smartFilterRuntime.d.ts.map +1 -0
  139. package/dist/runtime/smartFilterRuntime.js +63 -0
  140. package/dist/runtime/smartFilterRuntime.js.map +1 -0
  141. package/dist/runtime/strongRef.d.ts +16 -0
  142. package/dist/runtime/strongRef.d.ts.map +1 -0
  143. package/dist/runtime/strongRef.js +9 -0
  144. package/dist/runtime/strongRef.js.map +1 -0
  145. package/dist/serialization/importCustomBlockDefinition.d.ts +15 -0
  146. package/dist/serialization/importCustomBlockDefinition.d.ts.map +1 -0
  147. package/dist/serialization/importCustomBlockDefinition.js +76 -0
  148. package/dist/serialization/importCustomBlockDefinition.js.map +1 -0
  149. package/dist/serialization/index.d.ts +9 -0
  150. package/dist/serialization/index.d.ts.map +1 -0
  151. package/dist/serialization/index.js +11 -0
  152. package/dist/serialization/index.js.map +1 -0
  153. package/dist/serialization/serializedBlockDefinition.d.ts +12 -0
  154. package/dist/serialization/serializedBlockDefinition.d.ts.map +1 -0
  155. package/dist/serialization/serializedBlockDefinition.js +2 -0
  156. package/dist/serialization/serializedBlockDefinition.js.map +1 -0
  157. package/dist/serialization/serializedShaderBlockDefinition.d.ts +7 -0
  158. package/dist/serialization/serializedShaderBlockDefinition.d.ts.map +1 -0
  159. package/dist/serialization/serializedShaderBlockDefinition.js +2 -0
  160. package/dist/serialization/serializedShaderBlockDefinition.js.map +1 -0
  161. package/dist/serialization/serializedSmartFilter.d.ts +6 -0
  162. package/dist/serialization/serializedSmartFilter.d.ts.map +1 -0
  163. package/dist/serialization/serializedSmartFilter.js +2 -0
  164. package/dist/serialization/serializedSmartFilter.js.map +1 -0
  165. package/dist/serialization/smartFilterDeserializer.d.ts +34 -0
  166. package/dist/serialization/smartFilterDeserializer.d.ts.map +1 -0
  167. package/dist/serialization/smartFilterDeserializer.js +141 -0
  168. package/dist/serialization/smartFilterDeserializer.js.map +1 -0
  169. package/dist/serialization/smartFilterSerializer.d.ts +23 -0
  170. package/dist/serialization/smartFilterSerializer.d.ts.map +1 -0
  171. package/dist/serialization/smartFilterSerializer.js +95 -0
  172. package/dist/serialization/smartFilterSerializer.js.map +1 -0
  173. package/dist/serialization/v1/defaultBlockSerializer.d.ts +9 -0
  174. package/dist/serialization/v1/defaultBlockSerializer.d.ts.map +1 -0
  175. package/dist/serialization/v1/defaultBlockSerializer.js +19 -0
  176. package/dist/serialization/v1/defaultBlockSerializer.js.map +1 -0
  177. package/dist/serialization/v1/index.d.ts +4 -0
  178. package/dist/serialization/v1/index.d.ts.map +1 -0
  179. package/dist/serialization/v1/index.js +5 -0
  180. package/dist/serialization/v1/index.js.map +1 -0
  181. package/dist/serialization/v1/shaderBlockSerialization.types.d.ts +73 -0
  182. package/dist/serialization/v1/shaderBlockSerialization.types.d.ts.map +1 -0
  183. package/dist/serialization/v1/shaderBlockSerialization.types.js +7 -0
  184. package/dist/serialization/v1/shaderBlockSerialization.types.js.map +1 -0
  185. package/dist/serialization/v1/smartFilterSerialization.types.d.ts +98 -0
  186. package/dist/serialization/v1/smartFilterSerialization.types.d.ts.map +1 -0
  187. package/dist/serialization/v1/smartFilterSerialization.types.js +2 -0
  188. package/dist/serialization/v1/smartFilterSerialization.types.js.map +1 -0
  189. package/dist/smartFilter.d.ts +118 -0
  190. package/dist/smartFilter.d.ts.map +1 -0
  191. package/dist/smartFilter.js +169 -0
  192. package/dist/smartFilter.js.map +1 -0
  193. package/dist/utils/buildTools/buildShaders.d.ts +9 -0
  194. package/dist/utils/buildTools/buildShaders.d.ts.map +1 -0
  195. package/dist/utils/buildTools/buildShaders.js +13 -0
  196. package/dist/utils/buildTools/buildShaders.js.map +1 -0
  197. package/dist/utils/buildTools/convertGlslIntoBlock.d.ts +9 -0
  198. package/dist/utils/buildTools/convertGlslIntoBlock.d.ts.map +1 -0
  199. package/dist/utils/buildTools/convertGlslIntoBlock.js +346 -0
  200. package/dist/utils/buildTools/convertGlslIntoBlock.js.map +1 -0
  201. package/dist/utils/buildTools/convertGlslIntoShaderProgram.d.ts +26 -0
  202. package/dist/utils/buildTools/convertGlslIntoShaderProgram.d.ts.map +1 -0
  203. package/dist/utils/buildTools/convertGlslIntoShaderProgram.js +141 -0
  204. package/dist/utils/buildTools/convertGlslIntoShaderProgram.js.map +1 -0
  205. package/dist/utils/buildTools/convertShaders.d.ts +16 -0
  206. package/dist/utils/buildTools/convertShaders.d.ts.map +1 -0
  207. package/dist/utils/buildTools/convertShaders.js +62 -0
  208. package/dist/utils/buildTools/convertShaders.js.map +1 -0
  209. package/dist/utils/buildTools/shaderCode.types.d.ts +51 -0
  210. package/dist/utils/buildTools/shaderCode.types.d.ts.map +1 -0
  211. package/dist/utils/buildTools/shaderCode.types.js +2 -0
  212. package/dist/utils/buildTools/shaderCode.types.js.map +1 -0
  213. package/dist/utils/buildTools/shaderConverter.d.ts +77 -0
  214. package/dist/utils/buildTools/shaderConverter.d.ts.map +1 -0
  215. package/dist/utils/buildTools/shaderConverter.js +297 -0
  216. package/dist/utils/buildTools/shaderConverter.js.map +1 -0
  217. package/dist/utils/buildTools/watchShaders.d.ts +9 -0
  218. package/dist/utils/buildTools/watchShaders.d.ts.map +1 -0
  219. package/dist/utils/buildTools/watchShaders.js +39 -0
  220. package/dist/utils/buildTools/watchShaders.js.map +1 -0
  221. package/dist/utils/index.d.ts +4 -0
  222. package/dist/utils/index.d.ts.map +1 -0
  223. package/dist/utils/index.js +4 -0
  224. package/dist/utils/index.js.map +1 -0
  225. package/dist/utils/renderTargetUtils.d.ts +14 -0
  226. package/dist/utils/renderTargetUtils.d.ts.map +1 -0
  227. package/dist/utils/renderTargetUtils.js +23 -0
  228. package/dist/utils/renderTargetUtils.js.map +1 -0
  229. package/dist/utils/shaderCodeUtils.d.ts +91 -0
  230. package/dist/utils/shaderCodeUtils.d.ts.map +1 -0
  231. package/dist/utils/shaderCodeUtils.js +111 -0
  232. package/dist/utils/shaderCodeUtils.js.map +1 -0
  233. package/dist/utils/textureLoaders.d.ts +16 -0
  234. package/dist/utils/textureLoaders.d.ts.map +1 -0
  235. package/dist/utils/textureLoaders.js +22 -0
  236. package/dist/utils/textureLoaders.js.map +1 -0
  237. package/dist/utils/textureUtils.d.ts +13 -0
  238. package/dist/utils/textureUtils.d.ts.map +1 -0
  239. package/dist/utils/textureUtils.js +25 -0
  240. package/dist/utils/textureUtils.js.map +1 -0
  241. package/dist/utils/uniqueIdGenerator.d.ts +19 -0
  242. package/dist/utils/uniqueIdGenerator.d.ts.map +1 -0
  243. package/dist/utils/uniqueIdGenerator.js +27 -0
  244. package/dist/utils/uniqueIdGenerator.js.map +1 -0
  245. package/dist/version.d.ts +5 -0
  246. package/dist/version.d.ts.map +1 -0
  247. package/dist/version.js +5 -0
  248. package/dist/version.js.map +1 -0
  249. package/package.json +1 -1
  250. package/src/optimization/smartFilterOptimizer.ts +305 -158
  251. package/src/version.ts +1 -1
@@ -0,0 +1,666 @@
1
+ import { Logger } from "@onerjs/core/Misc/logger.js";
2
+ import { SmartFilter } from "../smartFilter.js";
3
+ import { ConnectionPointType } from "../connection/connectionPointType.js";
4
+ import { ShaderBlock } from "../blockFoundation/shaderBlock.js";
5
+ import { IsTextureInputBlock } from "../blockFoundation/inputBlock.js";
6
+ import { OptimizedShaderBlock } from "./optimizedShaderBlock.js";
7
+ import { AutoDisableMainInputColorName, DecorateChar, DecorateSymbol, GetShaderFragmentCode, UndecorateSymbol } from "../utils/shaderCodeUtils.js";
8
+ import { DependencyGraph } from "./dependencyGraph.js";
9
+ import { DisableableShaderBlock, BlockDisableStrategy } from "../blockFoundation/disableableShaderBlock.js";
10
+ import { TextureOptionsMatch } from "../blockFoundation/textureOptions.js";
11
+ const GetDefineRegEx = /^\S*#define\s+(\w+).*$/; // Matches a #define statement line, capturing its decorated or undecorated name
12
+ const ShowDebugData = false;
13
+ /**
14
+ * Optimizes a smart filter by aggregating blocks whenever possible, to reduce the number of draw calls.
15
+ */
16
+ export class SmartFilterOptimizer {
17
+ /**
18
+ * Creates a new smart filter optimizer
19
+ * @param smartFilter - The smart filter to optimize
20
+ * @param options - Options for the optimizer
21
+ */
22
+ constructor(smartFilter, options) {
23
+ this._blockStack = [];
24
+ this._blockToStackItem = new Map();
25
+ this._savedBlockStack = [];
26
+ this._savedBlockToStackItem = new Map();
27
+ this._symbolOccurrences = {};
28
+ this._remappedSymbols = [];
29
+ this._blockToMainFunctionName = new Map();
30
+ this._mainFunctionNameToCode = new Map();
31
+ this._dependencyGraph = new DependencyGraph();
32
+ this._forceUnoptimized = false;
33
+ this._sourceSmartFilter = smartFilter;
34
+ this._options = {
35
+ maxSamplersInFragmentShader: 8,
36
+ ...options,
37
+ };
38
+ }
39
+ /**
40
+ * Optimizes the smart filter by aggregating blocks whenever possible, to lower the number of rendering passes
41
+ * @returns The optimized smart filter, or null if the optimization failed
42
+ */
43
+ optimize() {
44
+ this._blockStack = [];
45
+ this._blockToStackItem = new Map();
46
+ let newSmartFilter = null;
47
+ this._sourceSmartFilter._workWithAggregateFreeGraph(() => {
48
+ if (this._sourceSmartFilter.output.connectedTo && !IsTextureInputBlock(this._sourceSmartFilter.output.connectedTo.ownerBlock)) {
49
+ const connectionsToReconnect = [];
50
+ if (this._options.removeDisabledBlocks) {
51
+ // Need to propagate runtime data to ensure we can tell if a block is disabled
52
+ this._sourceSmartFilter.output.ownerBlock.propagateRuntimeData();
53
+ const alreadyVisitedBlocks = new Set();
54
+ this._disconnectDisabledBlocks(this._sourceSmartFilter.output.connectedTo.ownerBlock, alreadyVisitedBlocks, connectionsToReconnect);
55
+ }
56
+ newSmartFilter = new SmartFilter(this._sourceSmartFilter.name + " - optimized");
57
+ // We must recheck isTextureInputBlock because all shader blocks may have been disconnected by the previous code
58
+ if (!IsTextureInputBlock(this._sourceSmartFilter.output.connectedTo.ownerBlock)) {
59
+ // Make sure all the connections in the graph have a runtimeData associated to them
60
+ // Note that the value of the runtimeData may not be set yet, we just need the objects to be created and propagated correctly
61
+ this._sourceSmartFilter.output.ownerBlock.prepareForRuntime();
62
+ this._sourceSmartFilter.output.ownerBlock.propagateRuntimeData();
63
+ const item = {
64
+ inputsToConnectTo: [newSmartFilter.output],
65
+ outputConnectionPoint: this._sourceSmartFilter.output.connectedTo,
66
+ };
67
+ this._blockStack.push(item);
68
+ this._blockToStackItem.set(item.outputConnectionPoint.ownerBlock, item);
69
+ while (this._blockStack.length > 0) {
70
+ const { inputsToConnectTo, outputConnectionPoint } = this._blockStack.pop();
71
+ const newBlock = this._processBlock(newSmartFilter, outputConnectionPoint);
72
+ if (newBlock) {
73
+ for (const inputToConnectTo of inputsToConnectTo) {
74
+ inputToConnectTo.connectTo(newBlock.output);
75
+ }
76
+ }
77
+ }
78
+ }
79
+ else {
80
+ newSmartFilter.output.connectTo(this._sourceSmartFilter.output.connectedTo);
81
+ }
82
+ if (this._options.removeDisabledBlocks) {
83
+ // We must reconnect the connections that were reconnected differently by the disconnect process, so that the original graph is left unmodified
84
+ for (const [input, connectedTo] of connectionsToReconnect) {
85
+ input.connectTo(connectedTo);
86
+ }
87
+ }
88
+ }
89
+ });
90
+ return newSmartFilter;
91
+ }
92
+ _disconnectDisabledBlocks(block, alreadyVisitedBlocks, inputsToReconnect) {
93
+ if (alreadyVisitedBlocks.has(block)) {
94
+ return;
95
+ }
96
+ alreadyVisitedBlocks.add(block);
97
+ for (const input of block.inputs) {
98
+ if (!input.connectedTo || input.type !== ConnectionPointType.Texture) {
99
+ continue;
100
+ }
101
+ this._disconnectDisabledBlocks(input.connectedTo.ownerBlock, alreadyVisitedBlocks, inputsToReconnect);
102
+ }
103
+ if (block instanceof DisableableShaderBlock && block.disabled.runtimeData.value) {
104
+ block.disconnectFromGraph(inputsToReconnect);
105
+ }
106
+ }
107
+ _initialize() {
108
+ this._symbolOccurrences = {};
109
+ this._remappedSymbols = [];
110
+ this._blockToMainFunctionName = new Map();
111
+ this._mainFunctionNameToCode = new Map();
112
+ this._dependencyGraph = new DependencyGraph();
113
+ this._vertexShaderCode = undefined;
114
+ this._currentOutputTextureOptions = undefined;
115
+ this._forceUnoptimized = false;
116
+ }
117
+ _makeSymbolUnique(symbolName) {
118
+ let newVarName = symbolName;
119
+ if (!this._symbolOccurrences[symbolName]) {
120
+ this._symbolOccurrences[symbolName] = 1;
121
+ }
122
+ else {
123
+ this._symbolOccurrences[symbolName]++;
124
+ newVarName += "_" + this._symbolOccurrences[symbolName];
125
+ }
126
+ return newVarName;
127
+ }
128
+ _processDefines(block, renameWork) {
129
+ const defines = block.getShaderProgram().fragment.defines;
130
+ if (!defines) {
131
+ return;
132
+ }
133
+ for (const define of defines) {
134
+ const match = define.match(GetDefineRegEx);
135
+ const defName = match?.[1];
136
+ if (!match || !defName) {
137
+ continue;
138
+ }
139
+ // See if we have already processed this define for this block type
140
+ const existingRemapped = this._remappedSymbols.find((s) => s.type === "define" && s.name === defName && s.owners[0] && s.owners[0].blockType === block.blockType);
141
+ let newDefName;
142
+ if (existingRemapped) {
143
+ newDefName = existingRemapped.remappedName;
144
+ }
145
+ else {
146
+ // Add the new define to the remapped symbols list
147
+ newDefName = DecorateSymbol(this._makeSymbolUnique(UndecorateSymbol(defName)));
148
+ this._remappedSymbols.push({
149
+ type: "define",
150
+ name: defName,
151
+ remappedName: newDefName,
152
+ declaration: define.replace(defName, newDefName), // No need to reconstruct the declaration
153
+ owners: [block],
154
+ inputBlock: undefined,
155
+ });
156
+ }
157
+ // Note the rename to be used later in all the functions (main and helper)
158
+ renameWork.symbolRenames.push({
159
+ from: defName,
160
+ to: newDefName,
161
+ });
162
+ }
163
+ }
164
+ /**
165
+ * Processes each helper function (any function that's not the main function), adding those to emit in the final
166
+ * block to _remappedSymbols and noting any necessary renames in renameWork. If a helper does not access any
167
+ * uniforms, it only needs to be emitted once regardless of how many instances of the block that define it are
168
+ * folded into the final optimized block.
169
+ * NOTE: so this function can know about the uniforms to test for them, it must be called after _processVariables.
170
+ * @param block - The block we are processing
171
+ * @param renameWork - The list of rename work to add to as needed
172
+ * @param samplerList - The list of sampler names
173
+ */
174
+ _processHelperFunctions(block, renameWork, samplerList) {
175
+ const functions = block.getShaderProgram().fragment.functions;
176
+ if (functions.length === 1) {
177
+ // There's only the main function, so we don't need to do anything
178
+ return;
179
+ }
180
+ for (const func of functions) {
181
+ let funcName = func.name;
182
+ if (funcName === block.getShaderProgram().fragment.mainFunctionName) {
183
+ continue;
184
+ }
185
+ funcName = UndecorateSymbol(funcName);
186
+ // Test to see if this function accesses any uniforms
187
+ let uniformsAccessed = [];
188
+ for (const sampler of samplerList) {
189
+ if (func.code.includes(sampler)) {
190
+ uniformsAccessed.push(sampler);
191
+ }
192
+ }
193
+ for (const remappedSymbol of this._remappedSymbols) {
194
+ if (remappedSymbol.type === "uniform" &&
195
+ remappedSymbol.owners[0] &&
196
+ remappedSymbol.owners[0].blockType === block.blockType &&
197
+ func.code.includes(remappedSymbol.remappedName)) {
198
+ uniformsAccessed.push(remappedSymbol.remappedName);
199
+ }
200
+ }
201
+ // Strip out any matches which are actually function params
202
+ const functionParams = func.params ? func.params.split(",").map((p) => p.trim().split(" ")[1]) : [];
203
+ uniformsAccessed = uniformsAccessed.filter((u) => !functionParams.includes(u));
204
+ // If it accessed any uniforms, throw an error
205
+ if (uniformsAccessed.length > 0) {
206
+ uniformsAccessed = uniformsAccessed.map((u) => (u[0] === DecorateChar ? UndecorateSymbol(u) : u));
207
+ throw new Error(`Helper function ${funcName} in blockType ${block.blockType} accesses uniform(s) ${uniformsAccessed.join(", ")} which is not supported. Pass them in instead.`);
208
+ }
209
+ // Look to see if we have an exact match including parameters of this function in the list of remapped symbols
210
+ const existingFunctionExactOverload = this._remappedSymbols.find((s) => s.type === "function" && s.name === funcName && s.params === func.params && s.owners[0] && s.owners[0].blockType === block.blockType);
211
+ // Look to see if we already have this function in the list of remapped symbols, regardless of parameters
212
+ const existingFunction = this._remappedSymbols.find((s) => s.type === "function" && s.name === funcName && s.owners[0] && s.owners[0].blockType === block.blockType);
213
+ // Get or create the remapped name, ignoring the parameter list
214
+ let remappedName = existingFunction?.remappedName;
215
+ let createdNewName = false;
216
+ if (!remappedName) {
217
+ remappedName = DecorateSymbol(this._makeSymbolUnique(funcName));
218
+ createdNewName = true;
219
+ // Since we've created a new name add it to the list of symbol renames
220
+ renameWork.symbolRenames.push({
221
+ from: DecorateSymbol(funcName),
222
+ to: remappedName,
223
+ });
224
+ }
225
+ // If we created a new name, or if we didn't but this exact overload wasn't found,
226
+ // add it to the list of remapped symbols so it'll be emitted in the final shader.
227
+ if (createdNewName || !existingFunctionExactOverload) {
228
+ this._remappedSymbols.push({
229
+ type: "function",
230
+ name: funcName,
231
+ remappedName,
232
+ params: func.params,
233
+ declaration: func.code,
234
+ owners: [block],
235
+ inputBlock: undefined,
236
+ });
237
+ }
238
+ }
239
+ }
240
+ _processVariables(block, renameWork, varDecl, declarations, hasValue = false, forceSingleInstance = false) {
241
+ if (!declarations) {
242
+ return [];
243
+ }
244
+ let rex = `${varDecl}\\s+(\\S+)\\s+${DecorateChar}(\\w+)${DecorateChar}\\s*`;
245
+ if (hasValue) {
246
+ rex += "=\\s*(.+);";
247
+ }
248
+ else {
249
+ rex += ";";
250
+ }
251
+ const samplerList = [];
252
+ const rx = new RegExp(rex, "g");
253
+ let match = rx.exec(declarations);
254
+ while (match !== null) {
255
+ const singleInstance = forceSingleInstance || varDecl === "const";
256
+ const varType = match[1];
257
+ const varName = match[2];
258
+ const varValue = hasValue ? match[3] : null;
259
+ let newVarName = null;
260
+ if (varType === "sampler2D") {
261
+ samplerList.push(DecorateSymbol(varName));
262
+ }
263
+ else {
264
+ const existingRemapped = this._remappedSymbols.find((s) => s.type === varDecl && s.name === varName && s.owners[0] && s.owners[0].blockType === block.blockType);
265
+ if (existingRemapped && singleInstance) {
266
+ newVarName = existingRemapped.remappedName;
267
+ if (varDecl === "uniform") {
268
+ existingRemapped.owners.push(block);
269
+ }
270
+ }
271
+ else {
272
+ newVarName = DecorateSymbol(this._makeSymbolUnique(varName));
273
+ this._remappedSymbols.push({
274
+ type: varDecl,
275
+ name: varName,
276
+ remappedName: newVarName,
277
+ declaration: `${varDecl} ${varType} ${newVarName}${hasValue ? " = " + varValue : ""};`,
278
+ owners: [block],
279
+ inputBlock: undefined,
280
+ });
281
+ }
282
+ }
283
+ if (newVarName) {
284
+ renameWork.symbolRenames.push({
285
+ from: DecorateSymbol(varName),
286
+ to: newVarName,
287
+ });
288
+ }
289
+ match = rx.exec(declarations);
290
+ }
291
+ return samplerList;
292
+ }
293
+ _processSampleTexture(block, renameWork, sampler, samplers, inputTextureBlock) {
294
+ let newSamplerName = sampler;
295
+ const existingRemapped = this._remappedSymbols.find((s) => s.type === "sampler" && s.inputBlock && s.inputBlock === inputTextureBlock);
296
+ if (existingRemapped) {
297
+ // The texture is shared by multiple blocks. We must reuse the same sampler name
298
+ newSamplerName = existingRemapped.remappedName;
299
+ }
300
+ else {
301
+ newSamplerName = DecorateSymbol(this._makeSymbolUnique(newSamplerName));
302
+ this._remappedSymbols.push({
303
+ type: "sampler",
304
+ name: sampler,
305
+ remappedName: newSamplerName,
306
+ declaration: `uniform sampler2D ${newSamplerName};`,
307
+ owners: [block],
308
+ inputBlock: inputTextureBlock,
309
+ });
310
+ }
311
+ if (samplers.indexOf(newSamplerName) === -1) {
312
+ samplers.push(newSamplerName);
313
+ }
314
+ renameWork.samplerRenames.push({
315
+ from: sampler,
316
+ to: newSamplerName,
317
+ });
318
+ return UndecorateSymbol(newSamplerName);
319
+ }
320
+ _canBeOptimized(block) {
321
+ if (block.disableOptimization) {
322
+ return false;
323
+ }
324
+ if (block instanceof ShaderBlock) {
325
+ if (block.getShaderProgram().vertex !== this._vertexShaderCode) {
326
+ return false;
327
+ }
328
+ if (!TextureOptionsMatch(block.outputTextureOptions, this._currentOutputTextureOptions)) {
329
+ return false;
330
+ }
331
+ }
332
+ return true;
333
+ }
334
+ // Processes a block given one of its output connection point
335
+ // Returns the name of the main function in the shader code
336
+ _optimizeBlock(optimizedBlock, outputConnectionPoint, samplers) {
337
+ const block = outputConnectionPoint.ownerBlock;
338
+ if (!(block instanceof ShaderBlock)) {
339
+ throw `Unhandled block type! blockType=${block.blockType}`;
340
+ }
341
+ if (this._currentOutputTextureOptions === undefined) {
342
+ this._currentOutputTextureOptions = block.outputTextureOptions;
343
+ }
344
+ const shaderProgram = block.getShaderProgram();
345
+ if (!shaderProgram) {
346
+ throw new Error(`Shader program not found for block "${block.name}"!`);
347
+ }
348
+ this._vertexShaderCode = this._vertexShaderCode ?? shaderProgram.vertex;
349
+ // The operations we collect which we will apply to all functions of this block later
350
+ const renameWork = {
351
+ symbolRenames: [],
352
+ samplerRenames: [],
353
+ sampleToFunctionCallSwaps: [],
354
+ samplersToApplyAutoTo: [],
355
+ };
356
+ // Generates a unique name for the fragment main function (if not already generated)
357
+ const shaderFuncName = shaderProgram.fragment.mainFunctionName;
358
+ let newShaderFuncName = this._blockToMainFunctionName.get(block);
359
+ if (!newShaderFuncName) {
360
+ newShaderFuncName = UndecorateSymbol(shaderFuncName);
361
+ newShaderFuncName = DecorateSymbol(this._makeSymbolUnique(newShaderFuncName));
362
+ this._blockToMainFunctionName.set(block, newShaderFuncName);
363
+ this._dependencyGraph.addElement(newShaderFuncName);
364
+ }
365
+ // Processes the defines to make them unique
366
+ this._processDefines(block, renameWork);
367
+ // Processes the constants to make them unique
368
+ this._processVariables(block, renameWork, "const", shaderProgram.fragment.const, true);
369
+ // Processes the uniform inputs to make them unique. Also extract the list of samplers
370
+ let samplerList = [];
371
+ samplerList = this._processVariables(block, renameWork, "uniform", shaderProgram.fragment.uniform, false);
372
+ let additionalSamplers = [];
373
+ additionalSamplers = this._processVariables(block, renameWork, "uniform", shaderProgram.fragment.uniformSingle, false, true);
374
+ samplerList.push(...additionalSamplers);
375
+ // Processes the functions other than the main function - must be done after _processVariables()
376
+ this._processHelperFunctions(block, renameWork, samplerList);
377
+ // Processes the texture inputs
378
+ for (const sampler of samplerList) {
379
+ const samplerName = UndecorateSymbol(sampler);
380
+ const input = block.findInput(samplerName);
381
+ if (!input) {
382
+ // No connection point found corresponding to this texture: it must be a texture used internally by the filter (here we are assuming that the shader code is not bugged!)
383
+ this._processSampleTexture(block, renameWork, samplerName, samplers);
384
+ continue;
385
+ }
386
+ // input found. Is it connected?
387
+ if (!input.connectedTo) {
388
+ throw `The connection point corresponding to the input named "${samplerName}" in block named "${block.name}" is not connected!`;
389
+ }
390
+ // If we are using the AutoSample strategy, we must preprocess the code that samples the texture
391
+ if (block instanceof DisableableShaderBlock && block.blockDisableStrategy === BlockDisableStrategy.AutoSample) {
392
+ renameWork.samplersToApplyAutoTo.push(sampler);
393
+ }
394
+ const parentBlock = input.connectedTo.ownerBlock;
395
+ if (IsTextureInputBlock(parentBlock)) {
396
+ // input is connected to an InputBlock of type "Texture": we must directly sample a texture
397
+ this._processSampleTexture(block, renameWork, samplerName, samplers, parentBlock);
398
+ }
399
+ else if (this._forceUnoptimized || !this._canBeOptimized(parentBlock)) {
400
+ // the block connected to this input cannot be optimized: we must directly sample its output texture
401
+ const uniqueSamplerName = this._processSampleTexture(block, renameWork, samplerName, samplers);
402
+ let stackItem = this._blockToStackItem.get(parentBlock);
403
+ if (!stackItem) {
404
+ stackItem = {
405
+ inputsToConnectTo: [],
406
+ outputConnectionPoint: input.connectedTo,
407
+ };
408
+ this._blockStack.push(stackItem);
409
+ this._blockToStackItem.set(parentBlock, stackItem);
410
+ }
411
+ // creates a new input connection point for the texture in the optimized block
412
+ const connectionPoint = optimizedBlock._registerInput(uniqueSamplerName, ConnectionPointType.Texture);
413
+ stackItem.inputsToConnectTo.push(connectionPoint);
414
+ }
415
+ else {
416
+ let parentFuncName;
417
+ if (this._blockToMainFunctionName.has(parentBlock)) {
418
+ // The parent block has already been processed. We can directly use the main function name
419
+ parentFuncName = this._blockToMainFunctionName.get(parentBlock);
420
+ }
421
+ else {
422
+ // Recursively processes the block connected to this input to get the main function name of the parent block
423
+ parentFuncName = this._optimizeBlock(optimizedBlock, input.connectedTo, samplers);
424
+ this._dependencyGraph.addDependency(newShaderFuncName, parentFuncName);
425
+ }
426
+ // The texture samplerName is not used anymore by the block, as it is replaced by a call to the main function of the parent block
427
+ // We remap it to an non existent sampler name, because the code that binds the texture still exists in the ShaderBinding.bind function.
428
+ // We don't want this code to have any effect, as it could overwrite (and remove) the texture binding of another block using this same sampler name!
429
+ this._remappedSymbols.push({
430
+ type: "sampler",
431
+ name: samplerName,
432
+ remappedName: "L(° O °L)",
433
+ declaration: ``,
434
+ owners: [block],
435
+ inputBlock: undefined,
436
+ });
437
+ // We have to replace the call(s) to __sampleTexture by a call to the main function of the parent block
438
+ renameWork.sampleToFunctionCallSwaps.push({ from: DecorateSymbol(samplerName), to: parentFuncName });
439
+ }
440
+ }
441
+ this._processAllFunctions(block, shaderProgram, renameWork, newShaderFuncName);
442
+ return newShaderFuncName;
443
+ }
444
+ /**
445
+ * Replaces calls to __sampleTexture(foo, uv); with calls to a function bar(uv); for chaining optimized blocks together
446
+ * @param code - The code to process
447
+ * @param samplerName - The old name of the sampler
448
+ * @param functionName - The name of the function to call instead
449
+ * @returns The updated code
450
+ */
451
+ _replaceSampleTextureWithFunctionCall(code, samplerName, functionName) {
452
+ const rx = new RegExp(`__sampleTexture\\s*\\(\\s*${samplerName}\\s*,\\s*(.*?)\\s*\\)`);
453
+ let match = rx.exec(code);
454
+ while (match !== null) {
455
+ const uv = match[1];
456
+ code = code.substring(0, match.index) + `${functionName}(${uv})` + code.substring(match.index + match[0].length);
457
+ match = rx.exec(code);
458
+ }
459
+ return code;
460
+ }
461
+ _replaceSampleTextureWithTexture2DCall(code, sampler, newSamplerName) {
462
+ const rx = new RegExp(`__sampleTexture\\s*\\(\\s*${DecorateChar}${sampler}${DecorateChar}\\s*,\\s*(.*?)\\s*\\)`);
463
+ let match = rx.exec(code);
464
+ while (match !== null) {
465
+ const uv = match[1];
466
+ code = code.substring(0, match.index) + `texture2D(${newSamplerName}, ${uv})` + code.substring(match.index + match[0].length);
467
+ match = rx.exec(code);
468
+ }
469
+ return code;
470
+ }
471
+ /**
472
+ * Processes all the functions, both main and helper functions, applying the renames and changes which have been collected
473
+ * @param block - The original block we are optimizing
474
+ * @param shaderProgram - The shader of the block we are optimizing
475
+ * @param renameWork - The rename work to apply
476
+ * @param newMainFunctionName - The new name for the main function
477
+ */
478
+ _processAllFunctions(block, shaderProgram, renameWork, newMainFunctionName) {
479
+ // Get the main function and process it
480
+ let declarationsAndMainFunction = GetShaderFragmentCode(shaderProgram, true);
481
+ declarationsAndMainFunction = this._processMainFunction(declarationsAndMainFunction, shaderProgram, newMainFunctionName);
482
+ declarationsAndMainFunction = this._processFunction(block, declarationsAndMainFunction, renameWork);
483
+ this._mainFunctionNameToCode.set(newMainFunctionName, declarationsAndMainFunction);
484
+ // Now process all the helper functions
485
+ this._remappedSymbols.forEach((remappedSymbol) => {
486
+ if (remappedSymbol.type === "function" && remappedSymbol.owners[0] && remappedSymbol.owners[0] === block) {
487
+ remappedSymbol.declaration = this._processFunction(block, remappedSymbol.declaration, renameWork);
488
+ }
489
+ });
490
+ }
491
+ /**
492
+ * Applies all required changes specific to just the main function
493
+ * @param code - The code of the main function
494
+ * @param shaderProgram - The shader program containing the main function
495
+ * @param newMainFunctionName - The new name for the main function
496
+ * @returns The updated main function code
497
+ */
498
+ _processMainFunction(code, shaderProgram, newMainFunctionName) {
499
+ // Replaces the main function name by the new one
500
+ code = code.replace(shaderProgram.fragment.mainFunctionName, newMainFunctionName);
501
+ // Removes the vUV declaration if it exists
502
+ code = code.replace(/varying\s+vec2\s+vUV\s*;/g, "");
503
+ return code;
504
+ }
505
+ /**
506
+ * Applies all required changes to a function (main or helper)
507
+ * @param block - The original block we are optimizing
508
+ * @param code - The code of the function
509
+ * @param renameWork - The rename work to apply
510
+ * @returns The updated function code
511
+ */
512
+ _processFunction(block, code, renameWork) {
513
+ // Replaces the texture2D calls by __sampleTexture for easier processing
514
+ code = code.replace(/(?<!\w)texture2D\s*\(/g, "__sampleTexture(");
515
+ for (const sampler of renameWork.samplersToApplyAutoTo) {
516
+ code = this._applyAutoSampleStrategy(code, sampler);
517
+ }
518
+ for (const rename of renameWork.symbolRenames) {
519
+ code = code.replace(new RegExp(`(?<!\\w)${rename.from}(?!\\w)`, "g"), rename.to);
520
+ }
521
+ for (const swap of renameWork.sampleToFunctionCallSwaps) {
522
+ code = this._replaceSampleTextureWithFunctionCall(code, swap.from, swap.to);
523
+ }
524
+ for (const rename of renameWork.samplerRenames) {
525
+ code = this._replaceSampleTextureWithTexture2DCall(code, rename.from, rename.to);
526
+ }
527
+ // Ensure all __sampleTexture( instances were replaced, and error out if not
528
+ if (code.indexOf("__sampleTexture(") > -1) {
529
+ throw new Error(`Could not optimize blockType ${block.blockType} because a texture2D() sampled something other than a uniform, which is unsupported`);
530
+ }
531
+ return code;
532
+ }
533
+ _saveBlockStackState() {
534
+ this._savedBlockStack = this._blockStack.slice();
535
+ this._savedBlockToStackItem = new Map();
536
+ for (const [key, value] of this._blockToStackItem) {
537
+ value.inputsToConnectTo = value.inputsToConnectTo.slice();
538
+ this._savedBlockToStackItem.set(key, value);
539
+ }
540
+ }
541
+ _restoreBlockStackState() {
542
+ this._blockStack.length = 0;
543
+ this._blockStack.push(...this._savedBlockStack);
544
+ this._blockToStackItem.clear();
545
+ for (const [key, value] of this._savedBlockToStackItem) {
546
+ this._blockToStackItem.set(key, value);
547
+ }
548
+ }
549
+ _processBlock(newSmartFilter, outputConnectionPoint) {
550
+ this._saveBlockStackState();
551
+ this._initialize();
552
+ let optimizedBlock = new OptimizedShaderBlock(newSmartFilter, "optimized");
553
+ const samplers = [];
554
+ let mainFuncName = this._optimizeBlock(optimizedBlock, outputConnectionPoint, samplers);
555
+ if (samplers.length > this._options.maxSamplersInFragmentShader) {
556
+ // Too many samplers for the optimized block.
557
+ // We must force the unoptimized mode and regenerate the block, which will be unoptimized this time
558
+ newSmartFilter.removeBlock(optimizedBlock);
559
+ this._initialize();
560
+ optimizedBlock = new OptimizedShaderBlock(newSmartFilter, "unoptimized");
561
+ this._forceUnoptimized = true;
562
+ samplers.length = 0;
563
+ this._restoreBlockStackState();
564
+ mainFuncName = this._optimizeBlock(optimizedBlock, outputConnectionPoint, samplers);
565
+ }
566
+ // Collects all the shader code
567
+ let code = "";
568
+ this._dependencyGraph.walk((element) => {
569
+ code += this._mainFunctionNameToCode.get(element) + "\n";
570
+ });
571
+ // Sets the remapping of the shader variables
572
+ const blockOwnerToShaderBinding = new Map();
573
+ const codeDefines = [];
574
+ let codeUniforms = "";
575
+ let codeConsts = "";
576
+ let codeHelperFunctions = "";
577
+ let codeHelperFunctionPrototypes = "";
578
+ for (const s of this._remappedSymbols) {
579
+ switch (s.type) {
580
+ case "define":
581
+ codeDefines.push(s.declaration);
582
+ break;
583
+ case "const":
584
+ codeConsts += s.declaration + "\n";
585
+ break;
586
+ case "uniform":
587
+ case "sampler":
588
+ codeUniforms += s.declaration + "\n";
589
+ break;
590
+ case "function":
591
+ codeHelperFunctionPrototypes += s.declaration.replace(/{[\s\S]*$/, ";\n");
592
+ codeHelperFunctions += s.declaration + "\n";
593
+ break;
594
+ }
595
+ for (const block of s.owners) {
596
+ let shaderBinding = blockOwnerToShaderBinding.get(block);
597
+ if (!shaderBinding) {
598
+ shaderBinding = block.getShaderBinding();
599
+ blockOwnerToShaderBinding.set(block, shaderBinding);
600
+ }
601
+ switch (s.type) {
602
+ case "uniform":
603
+ case "sampler":
604
+ shaderBinding.addShaderVariableRemapping(DecorateSymbol(s.name), s.remappedName);
605
+ break;
606
+ }
607
+ }
608
+ }
609
+ // Builds and sets the final shader code
610
+ code = codeHelperFunctionPrototypes + code + codeHelperFunctions;
611
+ if (ShowDebugData) {
612
+ code = code.replace(/^ {16}/gm, "");
613
+ code = code.replace(/\r/g, "");
614
+ code = code.replace(/\n(\n)*/g, "\n");
615
+ Logger.Log(`=================== BLOCK (forceUnoptimized=${this._forceUnoptimized}) ===================`);
616
+ Logger.Log(codeDefines.join("\n"));
617
+ Logger.Log(codeUniforms);
618
+ Logger.Log(codeConsts);
619
+ Logger.Log(code);
620
+ Logger.Log(`remappedSymbols=${this._remappedSymbols}`);
621
+ Logger.Log(`samplers=${samplers}`);
622
+ }
623
+ optimizedBlock.setShaderProgram({
624
+ vertex: this._vertexShaderCode,
625
+ fragment: {
626
+ defines: codeDefines,
627
+ const: codeConsts,
628
+ uniform: codeUniforms,
629
+ mainFunctionName: mainFuncName,
630
+ functions: [
631
+ {
632
+ name: mainFuncName,
633
+ params: "",
634
+ code,
635
+ },
636
+ ],
637
+ },
638
+ });
639
+ if (this._currentOutputTextureOptions !== undefined) {
640
+ optimizedBlock.outputTextureOptions = this._currentOutputTextureOptions;
641
+ }
642
+ optimizedBlock.setShaderBindings(Array.from(blockOwnerToShaderBinding.values()));
643
+ return optimizedBlock;
644
+ }
645
+ /**
646
+ * If this block used DisableStrategy.AutoSample, find all the __sampleTexture calls which just pass the vUV,
647
+ * skip the first one, and for all others replace with the local variable created by the DisableStrategy.AutoSample
648
+ *
649
+ * @param code - The shader code to process
650
+ * @param sampler - The name of the sampler
651
+ *
652
+ * @returns The processed code
653
+ */
654
+ _applyAutoSampleStrategy(code, sampler) {
655
+ let isFirstMatch = true;
656
+ const rx = new RegExp(`__sampleTexture\\s*\\(\\s*${sampler}\\s*,\\s*vUV\\s*\\)`, "g");
657
+ return code.replace(rx, (match) => {
658
+ if (isFirstMatch) {
659
+ isFirstMatch = false;
660
+ return match;
661
+ }
662
+ return DecorateSymbol(AutoDisableMainInputColorName);
663
+ });
664
+ }
665
+ }
666
+ //# sourceMappingURL=smartFilterOptimizer.js.map