@onerjs/smart-filters 8.25.1 → 8.25.3

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
@@ -10,7 +10,7 @@ import { ConnectionPointType } from "../connection/connectionPointType.js";
10
10
  import { ShaderBlock } from "../blockFoundation/shaderBlock.js";
11
11
  import { IsTextureInputBlock } from "../blockFoundation/inputBlock.js";
12
12
  import { OptimizedShaderBlock } from "./optimizedShaderBlock.js";
13
- import { AutoDisableMainInputColorName, DecorateChar, DecorateSymbol, GetShaderFragmentCode, UndecorateSymbol } from "../utils/shaderCodeUtils.js";
13
+ import { AutoDisableMainInputColorName, DecorateChar, DecorateSymbol, GetShaderFragmentCode, type ShaderProgram, UndecorateSymbol } from "../utils/shaderCodeUtils.js";
14
14
  import { DependencyGraph } from "./dependencyGraph.js";
15
15
  import { DisableableShaderBlock, BlockDisableStrategy } from "../blockFoundation/disableableShaderBlock.js";
16
16
  import { TextureOptionsMatch, type OutputTextureOptions } from "../blockFoundation/textureOptions.js";
@@ -18,6 +18,18 @@ import { TextureOptionsMatch, type OutputTextureOptions } from "../blockFoundati
18
18
  const GetDefineRegEx = /^\S*#define\s+(\w+).*$/; // Matches a #define statement line, capturing its decorated or undecorated name
19
19
  const ShowDebugData = false;
20
20
 
21
+ type Rename = {
22
+ from: string;
23
+ to: string;
24
+ };
25
+
26
+ type RenameWork = {
27
+ symbolRenames: Rename[];
28
+ samplerRenames: Rename[];
29
+ sampleToFunctionCallSwaps: Rename[];
30
+ samplersToApplyAutoTo: string[];
31
+ };
32
+
21
33
  /**
22
34
  * @internal
23
35
  */
@@ -231,10 +243,10 @@ export class SmartFilterOptimizer {
231
243
  return newVarName;
232
244
  }
233
245
 
234
- private _processDefines(block: ShaderBlock, code: string): string {
246
+ private _processDefines(block: ShaderBlock, renameWork: RenameWork) {
235
247
  const defines = block.getShaderProgram().fragment.defines;
236
248
  if (!defines) {
237
- return code;
249
+ return;
238
250
  }
239
251
 
240
252
  for (const define of defines) {
@@ -265,23 +277,32 @@ export class SmartFilterOptimizer {
265
277
  });
266
278
  }
267
279
 
268
- // Replace the define name in the main shader code
269
- code = code.replace(defName, newDefName);
280
+ // Note the rename to be used later in all the functions (main and helper)
281
+ renameWork.symbolRenames.push({
282
+ from: defName,
283
+ to: newDefName,
284
+ });
270
285
  }
271
-
272
- return code;
273
286
  }
274
287
 
275
- private _processHelperFunctions(block: ShaderBlock, code: string): string {
288
+ /**
289
+ * Processes each helper function (any function that's not the main function), adding those to emit in the final
290
+ * block to _remappedSymbols and noting any necessary renames in renameWork. If a helper does not access any
291
+ * uniforms, it only needs to be emitted once regardless of how many instances of the block that define it are
292
+ * folded into the final optimized block.
293
+ * NOTE: so this function can know about the uniforms to test for them, it must be called after _processVariables.
294
+ * @param block - The block we are processing
295
+ * @param renameWork - The list of rename work to add to as needed
296
+ * @param samplerList - The list of sampler names
297
+ */
298
+ private _processHelperFunctions(block: ShaderBlock, renameWork: RenameWork, samplerList: string[]): void {
276
299
  const functions = block.getShaderProgram().fragment.functions;
277
300
 
278
301
  if (functions.length === 1) {
279
302
  // There's only the main function, so we don't need to do anything
280
- return code;
303
+ return;
281
304
  }
282
305
 
283
- const replaceFuncNames: Array<[RegExp, string]> = [];
284
-
285
306
  for (const func of functions) {
286
307
  let funcName = func.name;
287
308
 
@@ -291,57 +312,83 @@ export class SmartFilterOptimizer {
291
312
 
292
313
  funcName = UndecorateSymbol(funcName);
293
314
 
294
- const regexFindCurName = new RegExp(DecorateSymbol(funcName), "g");
315
+ // Test to see if this function accesses any uniforms
316
+ let uniformsAccessed: string[] = [];
317
+ for (const sampler of samplerList) {
318
+ if (func.code.includes(sampler)) {
319
+ uniformsAccessed.push(sampler);
320
+ }
321
+ }
322
+ for (const remappedSymbol of this._remappedSymbols) {
323
+ if (
324
+ remappedSymbol.type === "uniform" &&
325
+ remappedSymbol.owners[0] &&
326
+ remappedSymbol.owners[0].blockType === block.blockType &&
327
+ func.code.includes(remappedSymbol.remappedName)
328
+ ) {
329
+ uniformsAccessed.push(remappedSymbol.remappedName);
330
+ }
331
+ }
332
+
333
+ // Strip out any matches which are actually function params
334
+ const functionParams = func.params ? func.params.split(",").map((p) => p.trim().split(" ")[1]) : [];
335
+ uniformsAccessed = uniformsAccessed.filter((u) => !functionParams.includes(u));
336
+
337
+ // If it accessed any uniforms, throw an error
338
+ if (uniformsAccessed.length > 0) {
339
+ uniformsAccessed = uniformsAccessed.map((u) => (u[0] === DecorateChar ? UndecorateSymbol(u) : u));
340
+ throw new Error(
341
+ `Helper function ${funcName} in blockType ${block.blockType} accesses uniform(s) ${uniformsAccessed.join(", ")} which is not supported. Pass them in instead.`
342
+ );
343
+ }
295
344
 
345
+ // Look to see if we have an exact match including parameters of this function in the list of remapped symbols
296
346
  const existingFunctionExactOverload = this._remappedSymbols.find(
297
347
  (s) => s.type === "function" && s.name === funcName && s.params === func.params && s.owners[0] && s.owners[0].blockType === block.blockType
298
348
  );
299
349
 
350
+ // Look to see if we already have this function in the list of remapped symbols, regardless of parameters
300
351
  const existingFunction = this._remappedSymbols.find((s) => s.type === "function" && s.name === funcName && s.owners[0] && s.owners[0].blockType === block.blockType);
301
352
 
302
353
  // Get or create the remapped name, ignoring the parameter list
303
- const newVarName = existingFunction?.remappedName ?? DecorateSymbol(this._makeSymbolUnique(funcName));
304
-
305
- // If the function name, regardless of params, wasn't found, add the rename mapping to our list
306
- if (!existingFunction) {
307
- replaceFuncNames.push([regexFindCurName, newVarName]);
354
+ let remappedName = existingFunction?.remappedName;
355
+ let createdNewName = false;
356
+ if (!remappedName) {
357
+ remappedName = DecorateSymbol(this._makeSymbolUnique(funcName));
358
+ createdNewName = true;
359
+ // Since we've created a new name add it to the list of symbol renames
360
+ renameWork.symbolRenames.push({
361
+ from: DecorateSymbol(funcName),
362
+ to: remappedName,
363
+ });
308
364
  }
309
365
 
310
- // If this exact overload wasn't found, add it to the list of remapped symbols so it'll be emitted in
311
- // the final shader.
312
- if (!existingFunctionExactOverload) {
313
- let funcCode = func.code;
314
- for (const [regex, replacement] of replaceFuncNames) {
315
- funcCode = funcCode.replace(regex, replacement);
316
- }
317
-
366
+ // If we created a new name, or if we didn't but this exact overload wasn't found,
367
+ // add it to the list of remapped symbols so it'll be emitted in the final shader.
368
+ if (createdNewName || !existingFunctionExactOverload) {
318
369
  this._remappedSymbols.push({
319
370
  type: "function",
320
371
  name: funcName,
321
- remappedName: newVarName,
372
+ remappedName,
322
373
  params: func.params,
323
- declaration: funcCode,
374
+ declaration: func.code,
324
375
  owners: [block],
325
376
  inputBlock: undefined,
326
377
  });
327
378
  }
328
-
329
- code = code.replace(regexFindCurName, newVarName);
330
379
  }
331
-
332
- return code;
333
380
  }
334
381
 
335
382
  private _processVariables(
336
383
  block: ShaderBlock,
337
- code: string,
384
+ renameWork: RenameWork,
338
385
  varDecl: "const" | "uniform",
339
386
  declarations?: string,
340
387
  hasValue = false,
341
388
  forceSingleInstance = false
342
- ): [string, Array<string>] {
389
+ ): Array<string> {
343
390
  if (!declarations) {
344
- return [code, []];
391
+ return [];
345
392
  }
346
393
 
347
394
  let rex = `${varDecl}\\s+(\\S+)\\s+${DecorateChar}(\\w+)${DecorateChar}\\s*`;
@@ -387,18 +434,25 @@ export class SmartFilterOptimizer {
387
434
  }
388
435
 
389
436
  if (newVarName) {
390
- code = code.replace(new RegExp(DecorateSymbol(varName), "g"), newVarName);
437
+ renameWork.symbolRenames.push({
438
+ from: DecorateSymbol(varName),
439
+ to: newVarName,
440
+ });
391
441
  }
392
442
 
393
443
  match = rx.exec(declarations);
394
444
  }
395
445
 
396
- return [code, samplerList];
446
+ return samplerList;
397
447
  }
398
448
 
399
- private _processSampleTexture(block: ShaderBlock, code: string, sampler: string, samplers: string[], inputTextureBlock?: InputBlock<ConnectionPointType.Texture>): string {
400
- const rx = new RegExp(`__sampleTexture\\s*\\(\\s*${DecorateChar}${sampler}${DecorateChar}\\s*,\\s*(.*?)\\s*\\)`);
401
-
449
+ private _processSampleTexture(
450
+ block: ShaderBlock,
451
+ renameWork: RenameWork,
452
+ sampler: string,
453
+ samplers: string[],
454
+ inputTextureBlock?: InputBlock<ConnectionPointType.Texture>
455
+ ): string {
402
456
  let newSamplerName = sampler;
403
457
 
404
458
  const existingRemapped = this._remappedSymbols.find((s) => s.type === "sampler" && s.inputBlock && s.inputBlock === inputTextureBlock);
@@ -422,16 +476,12 @@ export class SmartFilterOptimizer {
422
476
  samplers.push(newSamplerName);
423
477
  }
424
478
 
425
- let match = rx.exec(code);
426
- while (match !== null) {
427
- const uv = match[1]!;
428
-
429
- code = code.substring(0, match.index) + `texture2D(${newSamplerName}, ${uv})` + code.substring(match.index + match[0]!.length);
430
-
431
- match = rx.exec(code);
432
- }
479
+ renameWork.samplerRenames.push({
480
+ from: sampler,
481
+ to: newSamplerName,
482
+ });
433
483
 
434
- return code;
484
+ return UndecorateSymbol(newSamplerName);
435
485
  }
436
486
 
437
487
  private _canBeOptimized(block: BaseBlock): boolean {
@@ -457,146 +507,241 @@ export class SmartFilterOptimizer {
457
507
  private _optimizeBlock(optimizedBlock: OptimizedShaderBlock, outputConnectionPoint: ConnectionPoint, samplers: string[]): string {
458
508
  const block = outputConnectionPoint.ownerBlock;
459
509
 
460
- if (block instanceof ShaderBlock) {
461
- if (this._currentOutputTextureOptions === undefined) {
462
- this._currentOutputTextureOptions = block.outputTextureOptions;
463
- }
510
+ if (!(block instanceof ShaderBlock)) {
511
+ throw `Unhandled block type! blockType=${block.blockType}`;
512
+ }
464
513
 
465
- const shaderProgram = block.getShaderProgram();
514
+ if (this._currentOutputTextureOptions === undefined) {
515
+ this._currentOutputTextureOptions = block.outputTextureOptions;
516
+ }
466
517
 
467
- if (!shaderProgram) {
468
- throw new Error(`Shader program not found for block "${block.name}"!`);
469
- }
518
+ const shaderProgram = block.getShaderProgram();
519
+ if (!shaderProgram) {
520
+ throw new Error(`Shader program not found for block "${block.name}"!`);
521
+ }
470
522
 
471
- // We get the shader code of the main function only
472
- let code = GetShaderFragmentCode(shaderProgram, true);
523
+ this._vertexShaderCode = this._vertexShaderCode ?? shaderProgram.vertex;
473
524
 
474
- this._vertexShaderCode = this._vertexShaderCode ?? shaderProgram.vertex;
525
+ // The operations we collect which we will apply to all functions of this block later
526
+ const renameWork: RenameWork = {
527
+ symbolRenames: [],
528
+ samplerRenames: [],
529
+ sampleToFunctionCallSwaps: [],
530
+ samplersToApplyAutoTo: [],
531
+ };
475
532
 
476
- // Generates a unique name for the fragment main function (if not already generated)
477
- const shaderFuncName = shaderProgram.fragment.mainFunctionName;
533
+ // Generates a unique name for the fragment main function (if not already generated)
534
+ const shaderFuncName = shaderProgram.fragment.mainFunctionName;
478
535
 
479
- let newShaderFuncName = this._blockToMainFunctionName.get(block);
536
+ let newShaderFuncName = this._blockToMainFunctionName.get(block);
480
537
 
481
- if (!newShaderFuncName) {
482
- newShaderFuncName = UndecorateSymbol(shaderFuncName);
483
- newShaderFuncName = DecorateSymbol(this._makeSymbolUnique(newShaderFuncName));
538
+ if (!newShaderFuncName) {
539
+ newShaderFuncName = UndecorateSymbol(shaderFuncName);
540
+ newShaderFuncName = DecorateSymbol(this._makeSymbolUnique(newShaderFuncName));
484
541
 
485
- this._blockToMainFunctionName.set(block, newShaderFuncName);
486
- this._dependencyGraph.addElement(newShaderFuncName);
487
- }
542
+ this._blockToMainFunctionName.set(block, newShaderFuncName);
543
+ this._dependencyGraph.addElement(newShaderFuncName);
544
+ }
488
545
 
489
- // Replaces the main function name by the new one
490
- code = code.replace(shaderFuncName, newShaderFuncName);
546
+ // Processes the defines to make them unique
547
+ this._processDefines(block, renameWork);
491
548
 
492
- // Removes the vUV declaration if it exists
493
- code = code.replace(/varying\s+vec2\s+vUV\s*;/g, "");
549
+ // Processes the constants to make them unique
550
+ this._processVariables(block, renameWork, "const", shaderProgram.fragment.const, true);
494
551
 
495
- // Replaces the texture2D calls by __sampleTexture for easier processing
496
- code = code.replace(/(?<!\w)texture2D\s*\(/g, " __sampleTexture(");
552
+ // Processes the uniform inputs to make them unique. Also extract the list of samplers
553
+ let samplerList: string[] = [];
554
+ samplerList = this._processVariables(block, renameWork, "uniform", shaderProgram.fragment.uniform, false);
497
555
 
498
- // Processes the defines to make them unique
499
- code = this._processDefines(block, code);
556
+ let additionalSamplers = [];
557
+ additionalSamplers = this._processVariables(block, renameWork, "uniform", shaderProgram.fragment.uniformSingle, false, true);
500
558
 
501
- // Processes the functions other than the main function
502
- code = this._processHelperFunctions(block, code);
559
+ samplerList.push(...additionalSamplers);
503
560
 
504
- // Processes the constants to make them unique
505
- code = this._processVariables(block, code, "const", shaderProgram.fragment.const, true)[0];
561
+ // Processes the functions other than the main function - must be done after _processVariables()
562
+ this._processHelperFunctions(block, renameWork, samplerList);
506
563
 
507
- // Processes the uniform inputs to make them unique. Also extract the list of samplers
508
- let samplerList: string[] = [];
509
- [code, samplerList] = this._processVariables(block, code, "uniform", shaderProgram.fragment.uniform, false);
564
+ // Processes the texture inputs
565
+ for (const sampler of samplerList) {
566
+ const samplerName = UndecorateSymbol(sampler);
510
567
 
511
- let additionalSamplers = [];
512
- [code, additionalSamplers] = this._processVariables(block, code, "uniform", shaderProgram.fragment.uniformSingle, false, true);
568
+ const input = block.findInput(samplerName);
569
+ if (!input) {
570
+ // 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!)
571
+ this._processSampleTexture(block, renameWork, samplerName, samplers);
572
+ continue;
573
+ }
513
574
 
514
- samplerList.push(...additionalSamplers);
575
+ // input found. Is it connected?
576
+ if (!input.connectedTo) {
577
+ throw `The connection point corresponding to the input named "${samplerName}" in block named "${block.name}" is not connected!`;
578
+ }
515
579
 
516
- // Processes the texture inputs
517
- for (const sampler of samplerList) {
518
- const samplerName = UndecorateSymbol(sampler);
580
+ // If we are using the AutoSample strategy, we must preprocess the code that samples the texture
581
+ if (block instanceof DisableableShaderBlock && block.blockDisableStrategy === BlockDisableStrategy.AutoSample) {
582
+ renameWork.samplersToApplyAutoTo.push(sampler);
583
+ }
519
584
 
520
- const input = block.findInput(samplerName);
521
- if (!input) {
522
- // 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!)
523
- code = this._processSampleTexture(block, code, samplerName, samplers);
524
- continue;
585
+ const parentBlock = input.connectedTo.ownerBlock;
586
+
587
+ if (IsTextureInputBlock(parentBlock)) {
588
+ // input is connected to an InputBlock of type "Texture": we must directly sample a texture
589
+ this._processSampleTexture(block, renameWork, samplerName, samplers, parentBlock);
590
+ } else if (this._forceUnoptimized || !this._canBeOptimized(parentBlock)) {
591
+ // the block connected to this input cannot be optimized: we must directly sample its output texture
592
+ const uniqueSamplerName = this._processSampleTexture(block, renameWork, samplerName, samplers);
593
+ let stackItem = this._blockToStackItem.get(parentBlock);
594
+ if (!stackItem) {
595
+ stackItem = {
596
+ inputsToConnectTo: [],
597
+ outputConnectionPoint: input.connectedTo,
598
+ };
599
+ this._blockStack.push(stackItem);
600
+ this._blockToStackItem.set(parentBlock, stackItem);
525
601
  }
602
+ // creates a new input connection point for the texture in the optimized block
603
+ const connectionPoint = optimizedBlock._registerInput(uniqueSamplerName, ConnectionPointType.Texture);
604
+ stackItem.inputsToConnectTo.push(connectionPoint);
605
+ } else {
606
+ let parentFuncName: string;
526
607
 
527
- // input found. Is it connected?
528
- if (!input.connectedTo) {
529
- throw `The connection point corresponding to the input named "${samplerName}" in block named "${block.name}" is not connected!`;
608
+ if (this._blockToMainFunctionName.has(parentBlock)) {
609
+ // The parent block has already been processed. We can directly use the main function name
610
+ parentFuncName = this._blockToMainFunctionName.get(parentBlock)!;
611
+ } else {
612
+ // Recursively processes the block connected to this input to get the main function name of the parent block
613
+ parentFuncName = this._optimizeBlock(optimizedBlock, input.connectedTo, samplers);
614
+ this._dependencyGraph.addDependency(newShaderFuncName, parentFuncName);
530
615
  }
531
616
 
532
- // If we are using the AutoSample strategy, we must preprocess the code that samples the texture
533
- if (block instanceof DisableableShaderBlock && block.blockDisableStrategy === BlockDisableStrategy.AutoSample) {
534
- code = this._applyAutoSampleStrategy(code, sampler);
535
- }
617
+ // 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
618
+ // We remap it to an non existent sampler name, because the code that binds the texture still exists in the ShaderBinding.bind function.
619
+ // 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!
620
+ this._remappedSymbols.push({
621
+ type: "sampler",
622
+ name: samplerName,
623
+ remappedName: "L(° O °L)",
624
+ declaration: ``,
625
+ owners: [block],
626
+ inputBlock: undefined,
627
+ });
536
628
 
537
- const parentBlock = input.connectedTo.ownerBlock;
538
-
539
- if (IsTextureInputBlock(parentBlock)) {
540
- // input is connected to an InputBlock of type "Texture": we must directly sample a texture
541
- code = this._processSampleTexture(block, code, samplerName, samplers, parentBlock);
542
- } else if (this._forceUnoptimized || !this._canBeOptimized(parentBlock)) {
543
- // the block connected to this input cannot be optimized: we must directly sample its output texture
544
- code = this._processSampleTexture(block, code, samplerName, samplers);
545
- let stackItem = this._blockToStackItem.get(parentBlock);
546
- if (!stackItem) {
547
- stackItem = {
548
- inputsToConnectTo: [],
549
- outputConnectionPoint: input.connectedTo,
550
- };
551
- this._blockStack.push(stackItem);
552
- this._blockToStackItem.set(parentBlock, stackItem);
553
- }
554
- // creates a new input connection point for the texture in the optimized block
555
- const connectionPoint = optimizedBlock._registerInput(samplerName, ConnectionPointType.Texture);
556
- stackItem.inputsToConnectTo.push(connectionPoint);
557
- } else {
558
- let parentFuncName: string;
559
-
560
- if (this._blockToMainFunctionName.has(parentBlock)) {
561
- // The parent block has already been processed. We can directly use the main function name
562
- parentFuncName = this._blockToMainFunctionName.get(parentBlock)!;
563
- } else {
564
- // Recursively processes the block connected to this input to get the main function name of the parent block
565
- parentFuncName = this._optimizeBlock(optimizedBlock, input.connectedTo, samplers);
566
- this._dependencyGraph.addDependency(newShaderFuncName, parentFuncName);
567
- }
629
+ // We have to replace the call(s) to __sampleTexture by a call to the main function of the parent block
630
+ renameWork.sampleToFunctionCallSwaps.push({ from: DecorateSymbol(samplerName), to: parentFuncName });
631
+ }
632
+ }
568
633
 
569
- // 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
570
- // We remap it to an non existent sampler name, because the code that binds the texture still exists in the ShaderBinding.bind function.
571
- // 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!
572
- this._remappedSymbols.push({
573
- type: "sampler",
574
- name: samplerName,
575
- remappedName: "L(° O °L)",
576
- declaration: ``,
577
- owners: [block],
578
- inputBlock: undefined,
579
- });
634
+ this._processAllFunctions(block, shaderProgram, renameWork, newShaderFuncName);
635
+
636
+ return newShaderFuncName;
637
+ }
638
+
639
+ /**
640
+ * Replaces calls to __sampleTexture(foo, uv); with calls to a function bar(uv); for chaining optimized blocks together
641
+ * @param code - The code to process
642
+ * @param samplerName - The old name of the sampler
643
+ * @param functionName - The name of the function to call instead
644
+ * @returns The updated code
645
+ */
646
+ private _replaceSampleTextureWithFunctionCall(code: string, samplerName: string, functionName: string): string {
647
+ const rx = new RegExp(`__sampleTexture\\s*\\(\\s*${samplerName}\\s*,\\s*(.*?)\\s*\\)`);
580
648
 
581
- // We have to replace the call(s) to __sampleTexture by a call to the main function of the parent block
582
- const rx = new RegExp(`__sampleTexture\\s*\\(\\s*${sampler}\\s*,\\s*(.*?)\\s*\\)`);
649
+ let match = rx.exec(code);
650
+ while (match !== null) {
651
+ const uv = match[1];
583
652
 
584
- let match = rx.exec(code);
585
- while (match !== null) {
586
- const uv = match[1];
653
+ code = code.substring(0, match.index) + `${functionName}(${uv})` + code.substring(match.index + match[0]!.length);
654
+ match = rx.exec(code);
655
+ }
587
656
 
588
- code = code.substring(0, match.index) + `${parentFuncName}(${uv})` + code.substring(match.index + match[0]!.length);
589
- match = rx.exec(code);
590
- }
591
- }
657
+ return code;
658
+ }
659
+
660
+ private _replaceSampleTextureWithTexture2DCall(code: string, sampler: string, newSamplerName: string): string {
661
+ const rx = new RegExp(`__sampleTexture\\s*\\(\\s*${DecorateChar}${sampler}${DecorateChar}\\s*,\\s*(.*?)\\s*\\)`);
662
+ let match = rx.exec(code);
663
+ while (match !== null) {
664
+ const uv = match[1]!;
665
+
666
+ code = code.substring(0, match.index) + `texture2D(${newSamplerName}, ${uv})` + code.substring(match.index + match[0]!.length);
667
+
668
+ match = rx.exec(code);
669
+ }
670
+ return code;
671
+ }
672
+
673
+ /**
674
+ * Processes all the functions, both main and helper functions, applying the renames and changes which have been collected
675
+ * @param block - The original block we are optimizing
676
+ * @param shaderProgram - The shader of the block we are optimizing
677
+ * @param renameWork - The rename work to apply
678
+ * @param newMainFunctionName - The new name for the main function
679
+ */
680
+ private _processAllFunctions(block: ShaderBlock, shaderProgram: ShaderProgram, renameWork: RenameWork, newMainFunctionName: string) {
681
+ // Get the main function and process it
682
+ let declarationsAndMainFunction = GetShaderFragmentCode(shaderProgram, true);
683
+ declarationsAndMainFunction = this._processMainFunction(declarationsAndMainFunction, shaderProgram, newMainFunctionName);
684
+ declarationsAndMainFunction = this._processFunction(block, declarationsAndMainFunction, renameWork);
685
+ this._mainFunctionNameToCode.set(newMainFunctionName, declarationsAndMainFunction);
686
+
687
+ // Now process all the helper functions
688
+ this._remappedSymbols.forEach((remappedSymbol) => {
689
+ if (remappedSymbol.type === "function" && remappedSymbol.owners[0] && remappedSymbol.owners[0] === block) {
690
+ remappedSymbol.declaration = this._processFunction(block, remappedSymbol.declaration, renameWork);
592
691
  }
692
+ });
693
+ }
694
+
695
+ /**
696
+ * Applies all required changes specific to just the main function
697
+ * @param code - The code of the main function
698
+ * @param shaderProgram - The shader program containing the main function
699
+ * @param newMainFunctionName - The new name for the main function
700
+ * @returns The updated main function code
701
+ */
702
+ private _processMainFunction(code: string, shaderProgram: ShaderProgram, newMainFunctionName: string): string {
703
+ // Replaces the main function name by the new one
704
+ code = code.replace(shaderProgram.fragment.mainFunctionName, newMainFunctionName);
593
705
 
594
- this._mainFunctionNameToCode.set(newShaderFuncName, code);
706
+ // Removes the vUV declaration if it exists
707
+ code = code.replace(/varying\s+vec2\s+vUV\s*;/g, "");
595
708
 
596
- return newShaderFuncName;
709
+ return code;
710
+ }
711
+
712
+ /**
713
+ * Applies all required changes to a function (main or helper)
714
+ * @param block - The original block we are optimizing
715
+ * @param code - The code of the function
716
+ * @param renameWork - The rename work to apply
717
+ * @returns The updated function code
718
+ */
719
+ private _processFunction(block: ShaderBlock, code: string, renameWork: RenameWork): string {
720
+ // Replaces the texture2D calls by __sampleTexture for easier processing
721
+ code = code.replace(/(?<!\w)texture2D\s*\(/g, "__sampleTexture(");
722
+
723
+ for (const sampler of renameWork.samplersToApplyAutoTo) {
724
+ code = this._applyAutoSampleStrategy(code, sampler);
725
+ }
726
+
727
+ for (const rename of renameWork.symbolRenames) {
728
+ code = code.replace(new RegExp(`(?<!\\w)${rename.from}(?!\\w)`, "g"), rename.to);
597
729
  }
598
730
 
599
- throw `Unhandled block type! blockType=${block.blockType}`;
731
+ for (const swap of renameWork.sampleToFunctionCallSwaps) {
732
+ code = this._replaceSampleTextureWithFunctionCall(code, swap.from, swap.to);
733
+ }
734
+
735
+ for (const rename of renameWork.samplerRenames) {
736
+ code = this._replaceSampleTextureWithTexture2DCall(code, rename.from, rename.to);
737
+ }
738
+
739
+ // Ensure all __sampleTexture( instances were replaced, and error out if not
740
+ if (code.indexOf("__sampleTexture(") > -1) {
741
+ throw new Error(`Could not optimize blockType ${block.blockType} because a texture2D() sampled something other than a uniform, which is unsupported`);
742
+ }
743
+
744
+ return code;
600
745
  }
601
746
 
602
747
  private _saveBlockStackState(): void {
@@ -657,7 +802,8 @@ export class SmartFilterOptimizer {
657
802
  const codeDefines = [];
658
803
  let codeUniforms = "";
659
804
  let codeConsts = "";
660
- let codeFunctions = "";
805
+ let codeHelperFunctions = "";
806
+ let codeHelperFunctionPrototypes = "";
661
807
 
662
808
  for (const s of this._remappedSymbols) {
663
809
  switch (s.type) {
@@ -672,7 +818,8 @@ export class SmartFilterOptimizer {
672
818
  codeUniforms += s.declaration + "\n";
673
819
  break;
674
820
  case "function":
675
- codeFunctions += s.declaration + "\n";
821
+ codeHelperFunctionPrototypes += s.declaration.replace(/{[\s\S]*$/, ";\n");
822
+ codeHelperFunctions += s.declaration + "\n";
676
823
  break;
677
824
  }
678
825
 
@@ -693,7 +840,7 @@ export class SmartFilterOptimizer {
693
840
  }
694
841
 
695
842
  // Builds and sets the final shader code
696
- code = codeFunctions + code;
843
+ code = codeHelperFunctionPrototypes + code + codeHelperFunctions;
697
844
  if (ShowDebugData) {
698
845
  code = code.replace(/^ {16}/gm, "");
699
846
  code = code!.replace(/\r/g, "");
package/src/version.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  /**
2
2
  * The version of the SmartFilter core. During publish, this file is overwritten by recordVersionNumber.ts with the same version that is used for the NPM publish.
3
3
  */
4
- export const SmartFilterCoreVersion = "8.25.1";
4
+ export const SmartFilterCoreVersion = "8.25.3";