@babylonjs/smart-filters 0.1.0-alpha

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 (138) 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/blocks/aggregateBlock.d.ts +50 -0
  6. package/dist/blocks/aggregateBlock.d.ts.map +1 -0
  7. package/dist/blocks/aggregateBlock.js +103 -0
  8. package/dist/blocks/aggregateBlock.js.map +1 -0
  9. package/dist/blocks/baseBlock.d.ts +160 -0
  10. package/dist/blocks/baseBlock.d.ts.map +1 -0
  11. package/dist/blocks/baseBlock.js +256 -0
  12. package/dist/blocks/baseBlock.js.map +1 -0
  13. package/dist/blocks/copyBlock.d.ts +59 -0
  14. package/dist/blocks/copyBlock.d.ts.map +1 -0
  15. package/dist/blocks/copyBlock.js +84 -0
  16. package/dist/blocks/copyBlock.js.map +1 -0
  17. package/dist/blocks/disableableBlock.d.ts +30 -0
  18. package/dist/blocks/disableableBlock.d.ts.map +1 -0
  19. package/dist/blocks/disableableBlock.js +22 -0
  20. package/dist/blocks/disableableBlock.js.map +1 -0
  21. package/dist/blocks/inputBlock.d.ts +64 -0
  22. package/dist/blocks/inputBlock.d.ts.map +1 -0
  23. package/dist/blocks/inputBlock.js +74 -0
  24. package/dist/blocks/inputBlock.js.map +1 -0
  25. package/dist/blocks/outputBlock.d.ts +42 -0
  26. package/dist/blocks/outputBlock.d.ts.map +1 -0
  27. package/dist/blocks/outputBlock.js +74 -0
  28. package/dist/blocks/outputBlock.js.map +1 -0
  29. package/dist/blocks/shaderBlock.d.ts +68 -0
  30. package/dist/blocks/shaderBlock.d.ts.map +1 -0
  31. package/dist/blocks/shaderBlock.js +101 -0
  32. package/dist/blocks/shaderBlock.js.map +1 -0
  33. package/dist/command/command.d.ts +49 -0
  34. package/dist/command/command.d.ts.map +1 -0
  35. package/dist/command/command.js +15 -0
  36. package/dist/command/command.js.map +1 -0
  37. package/dist/command/commandBuffer.d.ts +40 -0
  38. package/dist/command/commandBuffer.d.ts.map +1 -0
  39. package/dist/command/commandBuffer.js +58 -0
  40. package/dist/command/commandBuffer.js.map +1 -0
  41. package/dist/command/commandBufferDebugger.d.ts +7 -0
  42. package/dist/command/commandBufferDebugger.d.ts.map +1 -0
  43. package/dist/command/commandBufferDebugger.js +12 -0
  44. package/dist/command/commandBufferDebugger.js.map +1 -0
  45. package/dist/connection/connectionPoint.d.ts +110 -0
  46. package/dist/connection/connectionPoint.d.ts.map +1 -0
  47. package/dist/connection/connectionPoint.js +153 -0
  48. package/dist/connection/connectionPoint.js.map +1 -0
  49. package/dist/connection/connectionPointCompatibilityState.d.ts +20 -0
  50. package/dist/connection/connectionPointCompatibilityState.d.ts.map +1 -0
  51. package/dist/connection/connectionPointCompatibilityState.js +32 -0
  52. package/dist/connection/connectionPointCompatibilityState.js.map +1 -0
  53. package/dist/connection/connectionPointDirection.d.ts +10 -0
  54. package/dist/connection/connectionPointDirection.d.ts.map +1 -0
  55. package/dist/connection/connectionPointDirection.js +11 -0
  56. package/dist/connection/connectionPointDirection.js.map +1 -0
  57. package/dist/connection/connectionPointType.d.ts +22 -0
  58. package/dist/connection/connectionPointType.d.ts.map +1 -0
  59. package/dist/connection/connectionPointType.js +17 -0
  60. package/dist/connection/connectionPointType.js.map +1 -0
  61. package/dist/connection/connectionPointWithDefault.d.ts +23 -0
  62. package/dist/connection/connectionPointWithDefault.d.ts.map +1 -0
  63. package/dist/connection/connectionPointWithDefault.js +19 -0
  64. package/dist/connection/connectionPointWithDefault.js.map +1 -0
  65. package/dist/index.d.ts +28 -0
  66. package/dist/index.d.ts.map +1 -0
  67. package/dist/index.js +28 -0
  68. package/dist/index.js.map +1 -0
  69. package/dist/optimization/dependencyGraph.d.ts +31 -0
  70. package/dist/optimization/dependencyGraph.d.ts.map +1 -0
  71. package/dist/optimization/dependencyGraph.js +77 -0
  72. package/dist/optimization/dependencyGraph.js.map +1 -0
  73. package/dist/optimization/optimizedShaderBlock.d.ts +75 -0
  74. package/dist/optimization/optimizedShaderBlock.d.ts.map +1 -0
  75. package/dist/optimization/optimizedShaderBlock.js +105 -0
  76. package/dist/optimization/optimizedShaderBlock.js.map +1 -0
  77. package/dist/optimization/smartFilterOptimizer.d.ts +72 -0
  78. package/dist/optimization/smartFilterOptimizer.d.ts.map +1 -0
  79. package/dist/optimization/smartFilterOptimizer.js +482 -0
  80. package/dist/optimization/smartFilterOptimizer.js.map +1 -0
  81. package/dist/runtime/renderTargetGenerator.d.ts +35 -0
  82. package/dist/runtime/renderTargetGenerator.d.ts.map +1 -0
  83. package/dist/runtime/renderTargetGenerator.js +153 -0
  84. package/dist/runtime/renderTargetGenerator.js.map +1 -0
  85. package/dist/runtime/shaderRuntime.d.ts +95 -0
  86. package/dist/runtime/shaderRuntime.d.ts.map +1 -0
  87. package/dist/runtime/shaderRuntime.js +120 -0
  88. package/dist/runtime/shaderRuntime.js.map +1 -0
  89. package/dist/runtime/smartFilterRuntime.d.ts +69 -0
  90. package/dist/runtime/smartFilterRuntime.d.ts.map +1 -0
  91. package/dist/runtime/smartFilterRuntime.js +57 -0
  92. package/dist/runtime/smartFilterRuntime.js.map +1 -0
  93. package/dist/runtime/strongRef.d.ts +16 -0
  94. package/dist/runtime/strongRef.d.ts.map +1 -0
  95. package/dist/runtime/strongRef.js +9 -0
  96. package/dist/runtime/strongRef.js.map +1 -0
  97. package/dist/smartFilter.d.ts +100 -0
  98. package/dist/smartFilter.d.ts.map +1 -0
  99. package/dist/smartFilter.js +154 -0
  100. package/dist/smartFilter.js.map +1 -0
  101. package/dist/utils/shaderCodeUtils.d.ts +131 -0
  102. package/dist/utils/shaderCodeUtils.d.ts.map +1 -0
  103. package/dist/utils/shaderCodeUtils.js +115 -0
  104. package/dist/utils/shaderCodeUtils.js.map +1 -0
  105. package/dist/utils/textureLoaders.d.ts +14 -0
  106. package/dist/utils/textureLoaders.d.ts.map +1 -0
  107. package/dist/utils/textureLoaders.js +22 -0
  108. package/dist/utils/textureLoaders.js.map +1 -0
  109. package/license.md +21 -0
  110. package/package.json +47 -0
  111. package/readme.md +165 -0
  112. package/src/IDisposable.ts +9 -0
  113. package/src/blocks/aggregateBlock.ts +121 -0
  114. package/src/blocks/baseBlock.ts +341 -0
  115. package/src/blocks/copyBlock.ts +103 -0
  116. package/src/blocks/disableableBlock.ts +40 -0
  117. package/src/blocks/inputBlock.ts +114 -0
  118. package/src/blocks/outputBlock.ts +97 -0
  119. package/src/blocks/shaderBlock.ts +145 -0
  120. package/src/command/command.ts +60 -0
  121. package/src/command/commandBuffer.ts +71 -0
  122. package/src/command/commandBufferDebugger.ts +13 -0
  123. package/src/connection/connectionPoint.ts +212 -0
  124. package/src/connection/connectionPointCompatibilityState.ts +31 -0
  125. package/src/connection/connectionPointDirection.ts +9 -0
  126. package/src/connection/connectionPointType.ts +30 -0
  127. package/src/connection/connectionPointWithDefault.ts +35 -0
  128. package/src/index.ts +36 -0
  129. package/src/optimization/dependencyGraph.ts +94 -0
  130. package/src/optimization/optimizedShaderBlock.ts +133 -0
  131. package/src/optimization/smartFilterOptimizer.ts +706 -0
  132. package/src/runtime/renderTargetGenerator.ts +204 -0
  133. package/src/runtime/shaderRuntime.ts +155 -0
  134. package/src/runtime/smartFilterRuntime.ts +104 -0
  135. package/src/runtime/strongRef.ts +18 -0
  136. package/src/smartFilter.ts +227 -0
  137. package/src/utils/shaderCodeUtils.ts +242 -0
  138. package/src/utils/textureLoaders.ts +28 -0
@@ -0,0 +1,103 @@
1
+ import type { Effect } from "@babylonjs/core/Materials/effect";
2
+ import type { ThinTexture } from "@babylonjs/core/Materials/Textures/thinTexture";
3
+
4
+ import type { ShaderProgram } from "../utils/shaderCodeUtils";
5
+ import type { SmartFilter } from "../smartFilter";
6
+ import type { StrongRef } from "../runtime/strongRef";
7
+ import { ConnectionPointType } from "../connection/connectionPointType.js";
8
+ import { ShaderBlock } from "./shaderBlock.js";
9
+ import { ShaderBinding } from "../runtime/shaderRuntime.js";
10
+
11
+ const shaderProgram: ShaderProgram = {
12
+ fragment: {
13
+ uniform: `
14
+ uniform sampler2D _input_;
15
+ `,
16
+
17
+ mainFunctionName: "_copy_",
18
+
19
+ functions: [
20
+ {
21
+ name: "_copy_",
22
+ code: `
23
+ vec4 _copy_(vec2 vUV) {
24
+ return texture2D(_input_, vUV);
25
+ }
26
+ `,
27
+ },
28
+ ],
29
+ },
30
+ };
31
+
32
+ /**
33
+ * The shader bindings for the Copy block.
34
+ */
35
+ export class CopyShaderBinding extends ShaderBinding {
36
+ private readonly _inputTexture: StrongRef<ThinTexture>;
37
+
38
+ /**
39
+ * Creates a new shader binding instance for the copy block.
40
+ * @param parentBlock - The parent block
41
+ * @param inputTexture - defines the input texture to copy
42
+ */
43
+ constructor(parentBlock: CopyBlock, inputTexture: StrongRef<ThinTexture>) {
44
+ super(parentBlock);
45
+ this._inputTexture = inputTexture;
46
+ }
47
+
48
+ /**
49
+ * Binds all the required data to the shader when rendering.
50
+ * @param effect - defines the effect to bind the data to
51
+ * @internal
52
+ */
53
+ public override bind(effect: Effect): void {
54
+ effect.setTexture(this.getRemappedName("input"), this._inputTexture.value);
55
+ }
56
+ }
57
+
58
+ /**
59
+ * A block responsible for copying a texture to the output.
60
+ *
61
+ * This might be helpful to duplicate a texture if necessary.
62
+ *
63
+ * It simply takes a texture as input and outputs it to another texture or the main canvas.
64
+ */
65
+ export class CopyBlock extends ShaderBlock {
66
+ /**
67
+ * The class name of the block.
68
+ */
69
+ public static override ClassName = "CopyBlock";
70
+
71
+ /**
72
+ * The input connection point of the block.
73
+ */
74
+ public readonly input = this._registerInput("input", ConnectionPointType.Texture);
75
+
76
+ /**
77
+ * The shader program (vertex and fragment code) to use to render the block
78
+ */
79
+ public static override ShaderCode = shaderProgram;
80
+
81
+ /**
82
+ * Create a new copy block.
83
+ * @param smartFilter - The smart filter this block belongs to.
84
+ * @param name -The friendly name of the block.
85
+ */
86
+ constructor(smartFilter: SmartFilter, name: string) {
87
+ super(smartFilter, name);
88
+ }
89
+
90
+ /**
91
+ * Get the class instance that binds all the required data to the shader (effect) when rendering.
92
+ * @returns The class instance that binds the data to the effect
93
+ */
94
+ public getShaderBinding(): ShaderBinding {
95
+ const input = this.input.runtimeData;
96
+
97
+ if (!input) {
98
+ throw new Error(`The input texture is missing for the CopyBlock named ${this.name}`);
99
+ }
100
+
101
+ return new CopyShaderBinding(this, input);
102
+ }
103
+ }
@@ -0,0 +1,40 @@
1
+ import type { SmartFilter } from "../smartFilter";
2
+ import type { ConnectionPoint } from "../connection/connectionPoint";
3
+
4
+ import { BaseBlock } from "../blocks/baseBlock.js";
5
+ import { ConnectionPointType } from "../connection/connectionPointType.js";
6
+ import { createStrongRef } from "../runtime/strongRef.js";
7
+
8
+ /**
9
+ * The interface that describes the disableable block.
10
+ */
11
+ export interface IDisableableBlock {
12
+ /**
13
+ * The disabled connection point of the block.
14
+ */
15
+ disabled: ConnectionPoint<ConnectionPointType.Boolean>;
16
+ }
17
+
18
+ /**
19
+ * A block that can be disabled.
20
+ */
21
+ export class DisableableBlock extends BaseBlock implements IDisableableBlock {
22
+ /**
23
+ * The disabled connection point of the block.
24
+ */
25
+ public readonly disabled = this._registerOptionalInput(
26
+ "disabled",
27
+ ConnectionPointType.Boolean,
28
+ createStrongRef(false)
29
+ );
30
+
31
+ /**
32
+ * Instantiates a new block.
33
+ * @param smartFilter - Defines the smart filter the block belongs to
34
+ * @param name - Defines the name of the block
35
+ * @param disableOptimization - Defines if the block should not be optimized (default: false)
36
+ */
37
+ constructor(smartFilter: SmartFilter, name: string, disableOptimization = false) {
38
+ super(smartFilter, name, disableOptimization);
39
+ }
40
+ }
@@ -0,0 +1,114 @@
1
+ import type { SmartFilter } from "../smartFilter";
2
+ import type { ConnectionPointValue } from "../connection/connectionPointType";
3
+ import type { RuntimeData } from "../connection/connectionPoint";
4
+ import type { ConnectionPointWithDefault } from "../connection/connectionPointWithDefault";
5
+ import type { DisableableBlock } from "./disableableBlock";
6
+ import { BaseBlock } from "../blocks/baseBlock.js";
7
+ import { createStrongRef } from "../runtime/strongRef.js";
8
+ import { ConnectionPointType } from "../connection/connectionPointType.js";
9
+
10
+ /**
11
+ * Type predicate to check if value is a strong ref or a direct value
12
+ * @param value - The value to check
13
+ * @returns true if the value is a strong ref, otherwise false
14
+ */
15
+ function isRuntimeData<U extends ConnectionPointType>(
16
+ value: ConnectionPointValue<U> | RuntimeData<U>
17
+ ): value is RuntimeData<U> {
18
+ return (value as RuntimeData<ConnectionPointType>).value !== undefined;
19
+ }
20
+
21
+ /**
22
+ * Predicate to check if a block is a texture input block.
23
+ * @param block - The block to check
24
+ * @returns true if the block is a texture input block, otherwise false
25
+ */
26
+ export function isTextureInputBlock(block: BaseBlock): block is InputBlock<ConnectionPointType.Texture> {
27
+ return (block as InputBlock<ConnectionPointType.Texture>).type === ConnectionPointType.Texture;
28
+ }
29
+
30
+ /**
31
+ * Predicate to check if a block is a disableable block.
32
+ * @param block - The block to check
33
+ * @returns true if the block is a disableable block, otherwise false
34
+ */
35
+ export function isDisableableBlock(block: BaseBlock): block is DisableableBlock {
36
+ return (block as DisableableBlock).disabled !== undefined;
37
+ }
38
+
39
+ /**
40
+ * This represents any inputs used in the graph.
41
+ *
42
+ * This is used to provide a way to connect the graph to the outside world.
43
+ *
44
+ * The value is dynamically set by the user.
45
+ */
46
+ export class InputBlock<U extends ConnectionPointType> extends BaseBlock {
47
+ /**
48
+ * The class name of the block.
49
+ */
50
+ public static override ClassName = "InputBlock";
51
+
52
+ /**
53
+ * The output connection point of the block.
54
+ */
55
+ public readonly output: ConnectionPointWithDefault<U>;
56
+
57
+ /**
58
+ * The type of the input.
59
+ */
60
+ public readonly type: U;
61
+
62
+ /**
63
+ * Gets the current value of the input.
64
+ */
65
+ public get runtimeValue(): RuntimeData<U> {
66
+ return this.output.runtimeData;
67
+ }
68
+
69
+ /**
70
+ * Sets the current value of the input.
71
+ */
72
+ public set runtimeValue(value: RuntimeData<U>) {
73
+ this.output.runtimeData = value;
74
+ }
75
+
76
+ /**
77
+ * Creates a new InputBlock.
78
+ * @param smartFilter - The smart filter to add the block to
79
+ * @param name - The friendly name of the block
80
+ * @param type - The type of the input
81
+ * @param initialValue - The initial value of the input
82
+ * @remarks the initial value can either be a strong reference or a value
83
+ */
84
+ constructor(
85
+ smartFilter: SmartFilter,
86
+ name: string,
87
+ type: U,
88
+ initialValue: ConnectionPointValue<U> | RuntimeData<U>
89
+ ) {
90
+ super(smartFilter, name);
91
+ this.type = type;
92
+
93
+ // Creates the output connection point
94
+ this.output = this._registerOutputWithDefault(
95
+ "output",
96
+ type,
97
+ isRuntimeData(initialValue) ? initialValue : createStrongRef(initialValue)
98
+ );
99
+
100
+ // Creates a strong reference to the initial value in case a reference has not been provided
101
+ if (isRuntimeData(initialValue)) {
102
+ this.runtimeValue = initialValue;
103
+ } else {
104
+ this.runtimeValue = createStrongRef(initialValue);
105
+ }
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Unionized type of all the possible input types.
111
+ */
112
+ export type AnyInputBlock = {
113
+ [T in keyof typeof ConnectionPointType]: InputBlock<(typeof ConnectionPointType)[T]>;
114
+ }[keyof typeof ConnectionPointType];
@@ -0,0 +1,97 @@
1
+ import type { InitializationData, SmartFilter } from "../smartFilter";
2
+ import { ConnectionPointType } from "../connection/connectionPointType.js";
3
+ import { BaseBlock } from "./baseBlock.js";
4
+ import { CopyBlock } from "./copyBlock.js";
5
+ import { ShaderRuntime } from "../runtime/shaderRuntime.js";
6
+ import { createCommand } from "../command/command.js";
7
+
8
+ /**
9
+ * The output block of a smart filter.
10
+ *
11
+ * Only the smart filter will internally create and host the output block.
12
+ * It should not be exported through the main index.ts module.
13
+ */
14
+ export class OutputBlock extends BaseBlock {
15
+ /**
16
+ * The class name of the block.
17
+ */
18
+ public static override ClassName = "OutputBlock";
19
+
20
+ /**
21
+ * Input connection point of the output block.
22
+ * This takes a texture as input.
23
+ */
24
+ public readonly input = this._registerInput("input", ConnectionPointType.Texture);
25
+
26
+ private _copyBlock: CopyBlock | null;
27
+
28
+ /**
29
+ * Create a new output block.
30
+ * @param smartFilter - The smart filter this block belongs to
31
+ */
32
+ constructor(smartFilter: SmartFilter) {
33
+ super(smartFilter, "output");
34
+
35
+ this._copyBlock = null;
36
+ }
37
+
38
+ private _getCopyBlock(): CopyBlock {
39
+ if (!this._copyBlock) {
40
+ this._copyBlock = new CopyBlock(this.smartFilter, "copy");
41
+ this._copyBlock.input.runtimeData = this.input.runtimeData;
42
+ }
43
+
44
+ return this._copyBlock;
45
+ }
46
+
47
+ /**
48
+ * Prepares all blocks for runtime by traversing the graph.
49
+ */
50
+ public override prepareForRuntime(): void {
51
+ this.visit({}, (block: BaseBlock, _extraData: Object) => {
52
+ if (block !== this) {
53
+ block.prepareForRuntime();
54
+ }
55
+ });
56
+ }
57
+
58
+ /**
59
+ * Propagates the runtime data for all graph blocks.
60
+ */
61
+ public override propagateRuntimeData(): void {
62
+ this.visit({}, (block: BaseBlock, _extraData: Object) => {
63
+ if (block !== this) {
64
+ block.propagateRuntimeData();
65
+ }
66
+ });
67
+ }
68
+
69
+ /**
70
+ * Generates the commands needed to execute the block at runtime and gathers promises for initialization work
71
+ * @param initializationData - The initialization data to use
72
+ * @param finalOutput - Defines if the block is the final output of the smart filter
73
+ */
74
+ public override generateCommandsAndGatherInitPromises(
75
+ initializationData: InitializationData,
76
+ finalOutput: boolean
77
+ ): void {
78
+ const copyBlock = this._getCopyBlock();
79
+ const runtime = initializationData.runtime;
80
+
81
+ const shaderBlockRuntime = new ShaderRuntime(
82
+ runtime.effectRenderer,
83
+ copyBlock.getShaderProgram(),
84
+ copyBlock.getShaderBinding()
85
+ );
86
+ initializationData.initializationPromises.push(shaderBlockRuntime.onReadyAsync);
87
+ runtime.registerResource(shaderBlockRuntime);
88
+
89
+ runtime.registerCommand(
90
+ createCommand(`${this.getClassName()}.renderToCanvas`, this, () => {
91
+ shaderBlockRuntime.renderToCanvas();
92
+ })
93
+ );
94
+
95
+ super.generateCommandsAndGatherInitPromises(initializationData, finalOutput);
96
+ }
97
+ }
@@ -0,0 +1,145 @@
1
+ import type { ThinRenderTargetTexture } from "@babylonjs/core/Materials/Textures/thinRenderTargetTexture";
2
+ import "@babylonjs/core/Engines/Extensions/engine.renderTarget.js";
3
+
4
+ import type { InitializationData, SmartFilter } from "../smartFilter";
5
+ import type { ShaderProgram } from "../utils/shaderCodeUtils";
6
+ import type { Binding } from "../runtime/shaderRuntime";
7
+ import type { ConnectionPoint } from "../connection/connectionPoint";
8
+ import { ShaderRuntime } from "../runtime/shaderRuntime.js";
9
+ import { ConnectionPointType } from "../connection/connectionPointType.js";
10
+ import { createCommand } from "../command/command.js";
11
+ import { DisableableBlock } from "./disableableBlock.js";
12
+ import { undecorateSymbol } from "../utils/shaderCodeUtils.js";
13
+
14
+ /**
15
+ * This is the base class for all shader blocks.
16
+ *
17
+ * It contains the redundant part of wrapping a shader for a full screen pass.
18
+ *
19
+ * The only required function to implement is the bind function.
20
+ */
21
+ export abstract class ShaderBlock extends DisableableBlock {
22
+ /**
23
+ * The class name of the block.
24
+ */
25
+ public static override ClassName = "ShaderBlock";
26
+
27
+ /**
28
+ * Get the class instance that binds all the required data to the shader (effect) when rendering.
29
+ * It should throw an error if required inputs are missing.
30
+ * @returns The class instance that binds the data to the effect
31
+ */
32
+ public abstract getShaderBinding(): Binding;
33
+
34
+ /**
35
+ * The shader program (vertex and fragment code) to use to render the block
36
+ */
37
+ public static ShaderCode: ShaderProgram;
38
+
39
+ /**
40
+ * The output connection point of the block.
41
+ */
42
+ public readonly output = this._registerOutput("output", ConnectionPointType.Texture);
43
+
44
+ protected _textureRatio: number = 1;
45
+
46
+ /**
47
+ * Gets the texture ratio of the output texture.
48
+ */
49
+ public get textureRatio() {
50
+ return this._textureRatio;
51
+ }
52
+
53
+ /**
54
+ * Sets the texture ratio of the output texture.
55
+ */
56
+ public set textureRatio(value: number) {
57
+ this._textureRatio = value;
58
+ }
59
+
60
+ /**
61
+ * Disconnects the block from the graph.
62
+ * @param disconnectedConnections - Stores the connections that have been broken in the process. You can reconnect them later if needed.
63
+ */
64
+ public override disconnectFromGraph(disconnectedConnections?: [ConnectionPoint, ConnectionPoint][]): void {
65
+ const input = this._getConnectionForMainInputTexture();
66
+
67
+ for (const endpoint of this.output.endpoints) {
68
+ disconnectedConnections?.push([endpoint, this.output]);
69
+ input.connectTo(endpoint);
70
+ }
71
+ }
72
+
73
+ protected _getConnectionForMainInputTexture(): ConnectionPoint {
74
+ const mainInputTextureName = this.getShaderProgram().fragment.mainInputTexture;
75
+ if (!mainInputTextureName) {
76
+ throw `The block named "${this.name}" does not have a main input texture defined!`;
77
+ }
78
+
79
+ const mainInputTexture = this.findInput(undecorateSymbol(mainInputTextureName));
80
+ if (!mainInputTexture || !mainInputTexture.connectedTo) {
81
+ throw `The main input texture "${mainInputTextureName}" of block named "${this.name}" is not connected!`;
82
+ }
83
+
84
+ return mainInputTexture.connectedTo;
85
+ }
86
+
87
+ /**
88
+ * Instantiates a new block.
89
+ * @param smartFilter - Defines the smart filter the block belongs to
90
+ * @param name - Defines the name of the block
91
+ * @param disableOptimization - Defines if the block should not be optimized (default: false)
92
+ */
93
+ constructor(smartFilter: SmartFilter, name: string, disableOptimization = false) {
94
+ super(smartFilter, name, disableOptimization);
95
+ }
96
+
97
+ /**
98
+ * Gets the shader program to use to render the block.
99
+ * @returns The shader program to use to render the block
100
+ */
101
+ public getShaderProgram() {
102
+ return (this.constructor as typeof ShaderBlock).ShaderCode;
103
+ }
104
+
105
+ /**
106
+ * Generates the commands needed to execute the block at runtime and gathers promises for initialization work
107
+ * @param initializationData - The initialization data to use
108
+ * @param finalOutput - Defines if the block is the final output of the smart filter
109
+ */
110
+ public override generateCommandsAndGatherInitPromises(
111
+ initializationData: InitializationData,
112
+ finalOutput: boolean
113
+ ): void {
114
+ const runtime = initializationData.runtime;
115
+ const shaderBlockRuntime = new ShaderRuntime(
116
+ runtime.effectRenderer,
117
+ this.getShaderProgram(),
118
+ this.getShaderBinding()
119
+ );
120
+ initializationData.initializationPromises.push(shaderBlockRuntime.onReadyAsync);
121
+ runtime.registerResource(shaderBlockRuntime);
122
+
123
+ if (finalOutput) {
124
+ runtime.registerCommand(
125
+ createCommand(`${this.getClassName()}.renderToCanvas`, this, () => {
126
+ shaderBlockRuntime.renderToCanvas();
127
+ })
128
+ );
129
+ } else {
130
+ const rtt =
131
+ this.output.runtimeData && (this.output.runtimeData.value as ThinRenderTargetTexture).renderTarget;
132
+ if (!rtt) {
133
+ throw new Error("ShaderBlock does not have a render target texture.");
134
+ }
135
+
136
+ runtime.registerCommand(
137
+ createCommand(`${this.getClassName()}.render`, this, () => {
138
+ shaderBlockRuntime.renderToTexture(rtt);
139
+ })
140
+ );
141
+ }
142
+
143
+ super.generateCommandsAndGatherInitPromises(initializationData, finalOutput);
144
+ }
145
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Represents the owner of a command.
3
+ * In practice, it will mostly be a block, the smart filter or a tool injecting commands.
4
+ */
5
+ export interface ICommandOwner {
6
+ /**
7
+ * The friendly name of the owner.
8
+ */
9
+ readonly name: string;
10
+
11
+ /**
12
+ * Gets the class name of the owner.
13
+ */
14
+ getClassName(): string;
15
+ }
16
+
17
+ /**
18
+ * Represents a the action of a @see Command. This is what will be executed during a command buffer execution.
19
+ */
20
+ export type CommandAction = () => void;
21
+
22
+ /**
23
+ * Represents a command to execute.
24
+ *
25
+ * A command contains a function that will be executed at runtime by the smart filter.
26
+ *
27
+ * It also contains the owner of the command for debugging purposes.
28
+ */
29
+ export type Command = {
30
+ /**
31
+ * The friendly name of the command.
32
+ */
33
+ readonly name: string;
34
+
35
+ /**
36
+ * The owner of the command.
37
+ * In practice, it will mostly be a block, the smart filter or a tool injecting commands.
38
+ */
39
+ readonly owner: ICommandOwner;
40
+
41
+ /**
42
+ * Defines the action to execute.
43
+ */
44
+ readonly action: CommandAction;
45
+ };
46
+
47
+ /**
48
+ * Creates a new command.
49
+ * @param name - The friendly name of the command
50
+ * @param owner - The owner of the command
51
+ * @param action - The action to execute when the command is executed
52
+ * @returns The new command
53
+ */
54
+ export function createCommand(name: string, owner: ICommandOwner, action: CommandAction): Command {
55
+ return {
56
+ name,
57
+ owner,
58
+ action,
59
+ };
60
+ }
@@ -0,0 +1,71 @@
1
+ import type { Command } from "./command";
2
+
3
+ /**
4
+ * Represents the action to run when calling `visitCommands` on a @see CommandBuffer.
5
+ */
6
+ export type CommandsVisitor = (command: Command) => void;
7
+
8
+ /**
9
+ * @see CommandsVisitor used to execute the commands of a @see CommandBuffer.
10
+ * @param command - The command to execute.
11
+ */
12
+ function executeCommandsVisitor(command: Command) {
13
+ command.action();
14
+ }
15
+
16
+ /**
17
+ * A command buffer is a list of commands to execute.
18
+ * This is used to store the list of tasks the current smart filter needs to execute.
19
+ */
20
+ export class CommandBuffer {
21
+ private readonly _commands: Command[] = [];
22
+
23
+ /**
24
+ * Creates a new command buffer.
25
+ * @param args - the list of commands to add to the command buffer
26
+ */
27
+ constructor(...args: Command[]) {
28
+ for (const command of args) {
29
+ this.push(command);
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Adds a command to the command buffer.
35
+ * @param command - the command to add
36
+ */
37
+ public push(command: Command) {
38
+ this._commands.push(command);
39
+ }
40
+
41
+ /**
42
+ * Clears the command buffer and empty the list of commands.
43
+ */
44
+ public clear() {
45
+ this._commands.length = 0;
46
+ }
47
+
48
+ /**
49
+ * Visits all the commands in the command buffer.
50
+ * @param commandVisitor - The action to execute on each command
51
+ */
52
+ public visitCommands(commandVisitor: CommandsVisitor): void {
53
+ for (const command of this._commands) {
54
+ commandVisitor(command);
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Execute all the commands in the command buffer.
60
+ */
61
+ public execute() {
62
+ this.visitCommands(executeCommandsVisitor);
63
+ }
64
+
65
+ /**
66
+ * Dispose the resources associated to the command buffer.
67
+ */
68
+ public dispose() {
69
+ this.clear();
70
+ }
71
+ }
@@ -0,0 +1,13 @@
1
+ import type { CommandBuffer } from "./commandBuffer";
2
+
3
+ /**
4
+ * Logs all the commands associated to a command buffer.
5
+ * @param commandBuffer - The command buffer to log
6
+ */
7
+ export function logCommands(commandBuffer: Readonly<CommandBuffer>) {
8
+ console.log("----- Command buffer commands -----");
9
+ commandBuffer.visitCommands((command) => {
10
+ console.log(` Owner: ${command.owner.getClassName()} (${command.owner.name}) - Command: ${command.name}`);
11
+ });
12
+ console.log("-----------------------------------");
13
+ }