@babylonjs/smart-filters 0.5.0-alpha → 0.6.1-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 (120) hide show
  1. package/dist/blocks/baseBlock.d.ts +6 -0
  2. package/dist/blocks/baseBlock.d.ts.map +1 -1
  3. package/dist/blocks/baseBlock.js +8 -0
  4. package/dist/blocks/baseBlock.js.map +1 -1
  5. package/dist/blocks/customShaderBlock.d.ts +55 -0
  6. package/dist/blocks/customShaderBlock.d.ts.map +1 -0
  7. package/dist/blocks/customShaderBlock.js +139 -0
  8. package/dist/blocks/customShaderBlock.js.map +1 -0
  9. package/dist/blocks/inputBlock.deserializer.d.ts +1 -1
  10. package/dist/blocks/inputBlock.deserializer.d.ts.map +1 -1
  11. package/dist/blocks/inputBlock.serializer.d.ts +1 -1
  12. package/dist/blocks/inputBlock.serializer.d.ts.map +1 -1
  13. package/dist/blocks/inputBlock.serializer.js +3 -3
  14. package/dist/blocks/inputBlock.serializer.js.map +1 -1
  15. package/dist/blocks/shaderBlock.js +2 -2
  16. package/dist/blocks/shaderBlock.js.map +1 -1
  17. package/dist/command/command.d.ts +2 -3
  18. package/dist/command/command.d.ts.map +1 -1
  19. package/dist/command/command.js.map +1 -1
  20. package/dist/command/commandBufferDebugger.js +1 -1
  21. package/dist/command/commandBufferDebugger.js.map +1 -1
  22. package/dist/connection/connectionPointType.d.ts +4 -0
  23. package/dist/connection/connectionPointType.d.ts.map +1 -1
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +2 -0
  27. package/dist/index.js.map +1 -1
  28. package/dist/optimization/smartFilterOptimizer.js +3 -3
  29. package/dist/optimization/smartFilterOptimizer.js.map +1 -1
  30. package/dist/serialization/importCustomShaderBlockDefinition.d.ts +11 -0
  31. package/dist/serialization/importCustomShaderBlockDefinition.d.ts.map +1 -0
  32. package/dist/serialization/importCustomShaderBlockDefinition.js +80 -0
  33. package/dist/serialization/importCustomShaderBlockDefinition.js.map +1 -0
  34. package/dist/serialization/index.d.ts +1 -0
  35. package/dist/serialization/index.d.ts.map +1 -1
  36. package/dist/serialization/index.js +1 -0
  37. package/dist/serialization/index.js.map +1 -1
  38. package/dist/serialization/serializedBlockDefinition.d.ts +7 -0
  39. package/dist/serialization/serializedBlockDefinition.d.ts.map +1 -0
  40. package/dist/serialization/serializedBlockDefinition.js +2 -0
  41. package/dist/serialization/serializedBlockDefinition.js.map +1 -0
  42. package/dist/serialization/serializedSmartFilter.d.ts +1 -1
  43. package/dist/serialization/serializedSmartFilter.d.ts.map +1 -1
  44. package/dist/serialization/smartFilterDeserializer.d.ts +12 -4
  45. package/dist/serialization/smartFilterDeserializer.d.ts.map +1 -1
  46. package/dist/serialization/smartFilterDeserializer.js +63 -34
  47. package/dist/serialization/smartFilterDeserializer.js.map +1 -1
  48. package/dist/serialization/smartFilterSerializer.d.ts +2 -2
  49. package/dist/serialization/smartFilterSerializer.d.ts.map +1 -1
  50. package/dist/serialization/smartFilterSerializer.js +9 -6
  51. package/dist/serialization/smartFilterSerializer.js.map +1 -1
  52. package/dist/serialization/v1/blockSerialization.types.d.ts +55 -0
  53. package/dist/serialization/v1/blockSerialization.types.d.ts.map +1 -0
  54. package/dist/serialization/v1/blockSerialization.types.js +7 -0
  55. package/dist/serialization/v1/blockSerialization.types.js.map +1 -0
  56. package/dist/serialization/v1/defaultBlockSerializer.d.ts +1 -1
  57. package/dist/serialization/v1/defaultBlockSerializer.d.ts.map +1 -1
  58. package/dist/serialization/v1/defaultBlockSerializer.js +1 -1
  59. package/dist/serialization/v1/defaultBlockSerializer.js.map +1 -1
  60. package/dist/serialization/v1/index.d.ts +1 -1
  61. package/dist/serialization/v1/index.d.ts.map +1 -1
  62. package/dist/serialization/v1/index.js +1 -1
  63. package/dist/serialization/v1/index.js.map +1 -1
  64. package/dist/serialization/v1/{serialization.types.d.ts → smartFilterSerialization.types.d.ts} +12 -11
  65. package/dist/serialization/v1/smartFilterSerialization.types.d.ts.map +1 -0
  66. package/dist/serialization/v1/smartFilterSerialization.types.js +2 -0
  67. package/dist/serialization/v1/smartFilterSerialization.types.js.map +1 -0
  68. package/dist/utils/buildTools/buildShaders.js +1 -1
  69. package/dist/utils/buildTools/buildShaders.js.map +1 -1
  70. package/dist/utils/buildTools/convertShaderForHardcodedBlock.d.ts +13 -0
  71. package/dist/utils/buildTools/convertShaderForHardcodedBlock.d.ts.map +1 -0
  72. package/dist/utils/buildTools/convertShaderForHardcodedBlock.js +116 -0
  73. package/dist/utils/buildTools/convertShaderForHardcodedBlock.js.map +1 -0
  74. package/dist/utils/buildTools/shaderCode.types.d.ts +43 -0
  75. package/dist/utils/buildTools/shaderCode.types.d.ts.map +1 -0
  76. package/dist/utils/buildTools/shaderCode.types.js +2 -0
  77. package/dist/utils/buildTools/shaderCode.types.js.map +1 -0
  78. package/dist/utils/buildTools/shaderConverter.d.ts +56 -8
  79. package/dist/utils/buildTools/shaderConverter.d.ts.map +1 -1
  80. package/dist/utils/buildTools/shaderConverter.js +87 -137
  81. package/dist/utils/buildTools/shaderConverter.js.map +1 -1
  82. package/dist/utils/buildTools/watchShaders.js +2 -2
  83. package/dist/utils/buildTools/watchShaders.js.map +1 -1
  84. package/dist/utils/renderTargetUtils.js +3 -3
  85. package/dist/utils/renderTargetUtils.js.map +1 -1
  86. package/dist/utils/shaderCodeUtils.d.ts +1 -42
  87. package/dist/utils/shaderCodeUtils.d.ts.map +1 -1
  88. package/dist/utils/shaderCodeUtils.js.map +1 -1
  89. package/package.json +1 -1
  90. package/readme.md +19 -15
  91. package/src/blocks/baseBlock.ts +9 -0
  92. package/src/blocks/customShaderBlock.ts +217 -0
  93. package/src/blocks/inputBlock.deserializer.ts +1 -1
  94. package/src/blocks/inputBlock.serializer.ts +4 -4
  95. package/src/blocks/shaderBlock.ts +2 -2
  96. package/src/command/command.ts +2 -3
  97. package/src/command/commandBufferDebugger.ts +1 -1
  98. package/src/connection/connectionPointType.ts +11 -0
  99. package/src/index.ts +2 -0
  100. package/src/optimization/smartFilterOptimizer.ts +3 -3
  101. package/src/serialization/importCustomShaderBlockDefinition.ts +85 -0
  102. package/src/serialization/index.ts +1 -0
  103. package/src/serialization/serializedBlockDefinition.ts +7 -0
  104. package/src/serialization/serializedSmartFilter.ts +1 -1
  105. package/src/serialization/smartFilterDeserializer.ts +106 -52
  106. package/src/serialization/smartFilterSerializer.ts +11 -7
  107. package/src/serialization/v1/blockSerialization.types.ts +63 -0
  108. package/src/serialization/v1/defaultBlockSerializer.ts +2 -2
  109. package/src/serialization/v1/index.ts +1 -1
  110. package/src/serialization/v1/{serialization.types.ts → smartFilterSerialization.types.ts} +11 -10
  111. package/src/utils/buildTools/buildShaders.ts +1 -1
  112. package/src/utils/buildTools/convertShaderForHardcodedBlock.ts +149 -0
  113. package/src/utils/buildTools/shaderCode.types.ts +49 -0
  114. package/src/utils/buildTools/shaderConverter.ts +158 -178
  115. package/src/utils/buildTools/watchShaders.ts +2 -2
  116. package/src/utils/renderTargetUtils.ts +3 -3
  117. package/src/utils/shaderCodeUtils.ts +1 -50
  118. package/dist/serialization/v1/serialization.types.d.ts.map +0 -1
  119. package/dist/serialization/v1/serialization.types.js +0 -2
  120. package/dist/serialization/v1/serialization.types.js.map +0 -1
@@ -267,7 +267,7 @@ export class SmartFilterOptimizer {
267
267
  s.type === "function" &&
268
268
  s.name === funcName &&
269
269
  s.owners[0] &&
270
- s.owners[0].getClassName() === block.getClassName()
270
+ s.owners[0].blockType === block.blockType
271
271
  );
272
272
 
273
273
  const newVarName = existingRemapped?.remappedName ?? decorateSymbol(this._makeSymbolUnique(funcName));
@@ -335,7 +335,7 @@ export class SmartFilterOptimizer {
335
335
  s.type === varDecl &&
336
336
  s.name === varName &&
337
337
  s.owners[0] &&
338
- s.owners[0].getClassName() === block.getClassName()
338
+ s.owners[0].blockType === block.blockType
339
339
  );
340
340
  if (existingRemapped && singleInstance) {
341
341
  newVarName = existingRemapped.remappedName;
@@ -591,7 +591,7 @@ export class SmartFilterOptimizer {
591
591
  return newShaderFuncName;
592
592
  }
593
593
 
594
- throw `Unhandled block type! className=${block.getClassName()}`;
594
+ throw `Unhandled block type! blockType=${block.blockType}`;
595
595
  }
596
596
 
597
597
  private _saveBlockStackState(): void {
@@ -0,0 +1,85 @@
1
+ import { ConnectionPointType } from "../connection/connectionPointType.js";
2
+ import { hasGlslHeader, parseFragmentShader } from "../utils/buildTools/shaderConverter.js";
3
+ import type { SerializedBlockDefinition } from "./serializedBlockDefinition.js";
4
+ import type { SerializedInputConnectionPointV1 } from "./v1/blockSerialization.types.js";
5
+
6
+ /**
7
+ * Imports a serialized custom shader block definition. Supports importing a JSON string
8
+ * of an SerializedBlockDefinition object, or a glsl shader with the required annotations
9
+ * so it can be converted to a SerializedBlockDefinition object.
10
+ * See readme.md for more information.
11
+ * @param serializedBlockDefinition - The serialized block definition - either a SerializedBlockDefinition object in a JSON string, or an annotated glsl shader
12
+ * @returns The serialized block definition
13
+ */
14
+ export function importCustomShaderBlockDefinition(serializedBlockDefinition: string): SerializedBlockDefinition {
15
+ if (hasGlslHeader(serializedBlockDefinition)) {
16
+ return importAnnotatedGlsl(serializedBlockDefinition);
17
+ } else {
18
+ // Assume this is a serialized SerializedBlockDefinition object
19
+ return JSON.parse(serializedBlockDefinition);
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Converts a fragment shader .glsl file to an SerializedBlockDefinition instance for use
25
+ * as a CustomShaderBlock. The .glsl file must contain certain annotations to be imported.
26
+ * See readme.md for more information.
27
+ * @param fragmentShader - The contents of the .glsl fragment shader file
28
+ * @returns The serialized block definition
29
+ */
30
+ function importAnnotatedGlsl(fragmentShader: string): SerializedBlockDefinition {
31
+ const fragmentShaderInfo = parseFragmentShader(fragmentShader);
32
+
33
+ if (!fragmentShaderInfo.blockType) {
34
+ throw new Error("blockType must be defined");
35
+ }
36
+
37
+ // Calculate the input connection points
38
+ const inputConnectionPoints: SerializedInputConnectionPointV1[] = [];
39
+ for (const uniform of fragmentShaderInfo.uniforms) {
40
+ // Convert to ConnectionPointType
41
+ let type: ConnectionPointType;
42
+ switch (uniform.type) {
43
+ case "float":
44
+ type = ConnectionPointType.Float;
45
+ break;
46
+ case "sampler2D":
47
+ type = ConnectionPointType.Texture;
48
+ break;
49
+ case "vec3":
50
+ type = ConnectionPointType.Color3;
51
+ break;
52
+ case "vec4":
53
+ type = ConnectionPointType.Color4;
54
+ break;
55
+ case "bool":
56
+ type = ConnectionPointType.Boolean;
57
+ break;
58
+ case "vec2":
59
+ type = ConnectionPointType.Vector2;
60
+ break;
61
+ default:
62
+ throw new Error(`Unsupported uniform type: '${uniform.type}'`);
63
+ }
64
+
65
+ // Add to input connection point list
66
+ const inputConnectionPoint: SerializedInputConnectionPointV1 = {
67
+ name: uniform.name,
68
+ type,
69
+ };
70
+ if (inputConnectionPoint.type !== ConnectionPointType.Texture && uniform.properties?.default !== undefined) {
71
+ inputConnectionPoint.defaultValue = uniform.properties.default;
72
+ }
73
+ inputConnectionPoints.push(inputConnectionPoint);
74
+ }
75
+
76
+ return {
77
+ formatVersion: 1,
78
+ blockType: fragmentShaderInfo.blockType,
79
+ shaderProgram: {
80
+ fragment: fragmentShaderInfo.shaderCode,
81
+ },
82
+ inputConnectionPoints,
83
+ disableOptimization: !!fragmentShaderInfo.disableOptimization,
84
+ };
85
+ }
@@ -2,3 +2,4 @@ export * from "./v1/index.js";
2
2
  export * from "./serializedSmartFilter.js";
3
3
  export * from "./smartFilterDeserializer.js";
4
4
  export * from "./smartFilterSerializer.js";
5
+ export * from "./serializedBlockDefinition.js";
@@ -0,0 +1,7 @@
1
+ import type { SerializedBlockDefinitionV1 } from "./v1/blockSerialization.types";
2
+
3
+ /**
4
+ * Type union of all versions of serialized SmartFilter block definitions
5
+ * A block definition is an object which is used to create a CustomShaderBlock instance.
6
+ */
7
+ export type SerializedBlockDefinition = SerializedBlockDefinitionV1;
@@ -1,4 +1,4 @@
1
- import type { SerializedSmartFilterV1 } from "./v1/serialization.types";
1
+ import type { SerializedSmartFilterV1 } from "./v1/smartFilterSerialization.types";
2
2
 
3
3
  /**
4
4
  * Type union of all versions of serialized SmartFilters
@@ -6,13 +6,22 @@ import { OutputBlock } from "../blocks/outputBlock.js";
6
6
  import type { ThinEngine } from "@babylonjs/core/Engines/thinEngine";
7
7
  import { InputBlock } from "../blocks/inputBlock.js";
8
8
  import type {
9
- DeserializeBlockV1,
10
9
  ISerializedBlockV1,
11
10
  ISerializedConnectionV1,
12
11
  OptionalBlockDeserializerV1,
13
12
  SerializedSmartFilterV1,
14
- } from "./v1/serialization.types";
13
+ } from "./v1/smartFilterSerialization.types";
15
14
  import { UniqueIdGenerator } from "../utils/uniqueIdGenerator.js";
15
+ import type { Nullable } from "@babylonjs/core/types";
16
+
17
+ /**
18
+ * A function that creates a block instance of the given class block type, or return null if it cannot.
19
+ */
20
+ export type BlockFactory = (
21
+ smartFilter: SmartFilter,
22
+ engine: ThinEngine,
23
+ serializedBlock: ISerializedBlockV1
24
+ ) => Promise<Nullable<BaseBlock>>;
16
25
 
17
26
  /**
18
27
  * Deserializes serialized SmartFilters. The caller passes in a map of block deserializers it wants to use,
@@ -20,39 +29,17 @@ import { UniqueIdGenerator } from "../utils/uniqueIdGenerator.js";
20
29
  * The deserializer supports versioned serialized SmartFilters.
21
30
  */
22
31
  export class SmartFilterDeserializer {
23
- private readonly _blockDeserializersV1: Map<string, DeserializeBlockV1> = new Map();
32
+ private readonly _blockFactory: BlockFactory;
33
+ private readonly _customInputBlockDeserializer?: OptionalBlockDeserializerV1;
24
34
 
25
35
  /**
26
36
  * Creates a new SmartFilterDeserializer
27
- * @param blockDeserializers - The map of block serializers to use, beyond those for the core blocks
37
+ * @param blockFactory - A function that creates a block of the given class name, or returns null if it cannot
28
38
  * @param customInputBlockDeserializer - An optional custom deserializer for InputBlocks - if supplied and it returns null, the default deserializer will be used
29
39
  */
30
- public constructor(
31
- blockDeserializers: Map<string, DeserializeBlockV1>,
32
- customInputBlockDeserializer?: OptionalBlockDeserializerV1
33
- ) {
34
- this._blockDeserializersV1 = blockDeserializers;
35
-
36
- this._blockDeserializersV1.set(
37
- InputBlock.ClassName,
38
- async (smartFilter: SmartFilter, serializedBlock: ISerializedBlockV1, engine: ThinEngine) => {
39
- if (customInputBlockDeserializer) {
40
- const customDeserializerResult = await customInputBlockDeserializer(
41
- smartFilter,
42
- serializedBlock,
43
- engine
44
- );
45
- if (customDeserializerResult !== null) {
46
- return customDeserializerResult;
47
- }
48
- }
49
- return inputBlockDeserializer(smartFilter, serializedBlock);
50
- }
51
- );
52
-
53
- this._blockDeserializersV1.set(OutputBlock.ClassName, (smartFilter: SmartFilter) =>
54
- Promise.resolve(smartFilter.output.ownerBlock)
55
- );
40
+ public constructor(blockFactory: BlockFactory, customInputBlockDeserializer?: OptionalBlockDeserializerV1) {
41
+ this._blockFactory = blockFactory;
42
+ this._customInputBlockDeserializer = customInputBlockDeserializer;
56
43
  }
57
44
 
58
45
  /**
@@ -63,7 +50,14 @@ export class SmartFilterDeserializer {
63
50
  */
64
51
  public async deserialize(engine: ThinEngine, smartFilterJson: any): Promise<SmartFilter> {
65
52
  const serializedSmartFilter: SerializedSmartFilter = smartFilterJson;
66
- switch (serializedSmartFilter.version) {
53
+
54
+ // Back-compat for the rename of version to formatVersion, didn't warrant a new version
55
+ if ((serializedSmartFilter as any).version && serializedSmartFilter.formatVersion === undefined) {
56
+ serializedSmartFilter.formatVersion = (serializedSmartFilter as any).version;
57
+ delete (serializedSmartFilter as any).version;
58
+ }
59
+
60
+ switch (serializedSmartFilter.formatVersion) {
67
61
  case 1:
68
62
  return await this._deserializeV1(engine, serializedSmartFilter);
69
63
  }
@@ -85,31 +79,28 @@ export class SmartFilterDeserializer {
85
79
 
86
80
  // Deserialize the blocks
87
81
  const blockDeserializationWork: Promise<void>[] = [];
82
+ const blockDefinitionsWhichCouldNotBeDeserialized: string[] = [];
88
83
  serializedSmartFilter.blocks.forEach((serializedBlock: ISerializedBlockV1) => {
89
- const blockDeserializer = this._blockDeserializersV1.get(serializedBlock.className);
90
- if (!blockDeserializer) {
91
- throw new Error(`No deserializer found for block type ${serializedBlock.className}`);
92
- }
93
84
  blockDeserializationWork.push(
94
- blockDeserializer(smartFilter, serializedBlock, engine).then((newBlock) => {
95
- // Deserializers are not responsible for setting the uniqueId or comments.
96
- // This is so they don't have to be passed into the constructors when programmatically creating
97
- // blocks, and so each deserializer doesn't have to remember to do it.
98
- newBlock.uniqueId = serializedBlock.uniqueId;
99
- newBlock.comments = serializedBlock.comments;
100
-
101
- // We need to ensure any uniqueIds generated in the future (e.g. a new block is added to the SmartFilter)
102
- // are higher than this one.
103
- UniqueIdGenerator.EnsureIdsGreaterThan(newBlock.uniqueId);
104
-
105
- // Save in the map
106
- blockIdMap.set(newBlock.uniqueId, newBlock);
107
- blockNameMap.set(newBlock.name, newBlock);
108
- })
85
+ this._deserializeBlockV1(
86
+ smartFilter,
87
+ serializedBlock,
88
+ engine,
89
+ blockDefinitionsWhichCouldNotBeDeserialized,
90
+ blockIdMap,
91
+ blockNameMap
92
+ )
109
93
  );
110
94
  });
111
95
  await Promise.all(blockDeserializationWork);
112
96
 
97
+ // If any block definitions could not be deserialized, throw an error
98
+ if (blockDefinitionsWhichCouldNotBeDeserialized.length > 0) {
99
+ throw new Error(
100
+ `Could not deserialize the following block definitions: ${blockDefinitionsWhichCouldNotBeDeserialized.join(", ")}`
101
+ );
102
+ }
103
+
113
104
  // Deserialize the connections
114
105
  serializedSmartFilter.connections.forEach((connection: ISerializedConnectionV1) => {
115
106
  // Find the source block and its connection point's connectTo function
@@ -121,7 +112,9 @@ export class SmartFilterDeserializer {
121
112
  if (!sourceBlock) {
122
113
  throw new Error(`Source block ${connection.outputBlock} not found`);
123
114
  }
124
- const sourceConnectionPoint = (sourceBlock as any)[connection.outputConnectionPoint];
115
+ const sourceConnectionPoint = sourceBlock.outputs.find(
116
+ (output) => output.name === connection.outputConnectionPoint
117
+ );
125
118
  if (!sourceConnectionPoint || typeof sourceConnectionPoint.connectTo !== "function") {
126
119
  throw new Error(
127
120
  `Block ${connection.outputBlock} does not have an connection point named ${connection.outputConnectionPoint}`
@@ -137,7 +130,10 @@ export class SmartFilterDeserializer {
137
130
  if (!targetBlock) {
138
131
  throw new Error(`Target block ${connection.inputBlock} not found`);
139
132
  }
140
- const targetConnectionPoint = (targetBlock as any)[connection.inputConnectionPoint];
133
+
134
+ const targetConnectionPoint = targetBlock.inputs.find(
135
+ (input) => input.name === connection.inputConnectionPoint
136
+ );
141
137
  if (!targetConnectionPoint || typeof targetConnectionPoint !== "object") {
142
138
  throw new Error(
143
139
  `Block ${connection.inputBlock} does not have a connection point named ${connection.inputConnectionPoint}`
@@ -150,4 +146,62 @@ export class SmartFilterDeserializer {
150
146
 
151
147
  return smartFilter;
152
148
  }
149
+
150
+ private async _deserializeBlockV1(
151
+ smartFilter: SmartFilter,
152
+ serializedBlock: ISerializedBlockV1,
153
+ engine: ThinEngine,
154
+ blockTypesWhichCouldNotBeDeserialized: string[],
155
+ blockIdMap: Map<number, BaseBlock>,
156
+ blockNameMap: Map<string, BaseBlock>
157
+ ): Promise<void> {
158
+ let newBlock: Nullable<BaseBlock> = null;
159
+
160
+ // Back compat for early Smart Filter V1 serialization where the blockType was stored in className
161
+ // Not worth creating a new version for this, as it's only used in the deserializer
162
+ if ((serializedBlock as any).className && !serializedBlock.blockType) {
163
+ serializedBlock.blockType = (serializedBlock as any).className;
164
+ }
165
+
166
+ // Get the instance of the block
167
+ switch (serializedBlock.blockType) {
168
+ case InputBlock.ClassName:
169
+ {
170
+ if (this._customInputBlockDeserializer) {
171
+ newBlock = await this._customInputBlockDeserializer(smartFilter, serializedBlock, engine);
172
+ }
173
+ if (newBlock === null) {
174
+ newBlock = inputBlockDeserializer(smartFilter, serializedBlock);
175
+ }
176
+ }
177
+ break;
178
+ case OutputBlock.ClassName:
179
+ {
180
+ newBlock = smartFilter.output.ownerBlock;
181
+ }
182
+ break;
183
+ default: {
184
+ // If it's not an input or output block, use the provided block factory
185
+ newBlock = await this._blockFactory(smartFilter, engine, serializedBlock);
186
+ if (!newBlock) {
187
+ blockTypesWhichCouldNotBeDeserialized.push(serializedBlock.blockType);
188
+ return;
189
+ }
190
+ }
191
+ }
192
+
193
+ // Deserializers are not responsible for setting the uniqueId or comments.
194
+ // This is so they don't have to be passed into the constructors when programmatically creating
195
+ // blocks, and so each deserializer doesn't have to remember to do it.
196
+ newBlock.uniqueId = serializedBlock.uniqueId;
197
+ newBlock.comments = serializedBlock.comments;
198
+
199
+ // We need to ensure any uniqueIds generated in the future (e.g. a new block is added to the SmartFilter)
200
+ // are higher than this one.
201
+ UniqueIdGenerator.EnsureIdsGreaterThan(newBlock.uniqueId);
202
+
203
+ // Save in the map
204
+ blockIdMap.set(newBlock.uniqueId, newBlock);
205
+ blockNameMap.set(newBlock.name, newBlock);
206
+ }
153
207
  }
@@ -10,7 +10,8 @@ import type {
10
10
  ISerializedConnectionV1,
11
11
  SerializeBlockV1,
12
12
  SerializedSmartFilterV1,
13
- } from "./v1/serialization.types";
13
+ } from "./v1/smartFilterSerialization.types";
14
+ import { CustomShaderBlock } from "../blocks/customShaderBlock.js";
14
15
 
15
16
  /**
16
17
  * Determines if two serialized connection points are equivalent to each other
@@ -37,17 +38,17 @@ export class SmartFilterSerializer {
37
38
 
38
39
  /**
39
40
  * Creates a new SmartFilterSerializer
40
- * @param blocksUsingDefaultSerialization - A list of the classNames of blocks which can use default serialization (they only have ConnectionPoint properties and no constructor parameters)
41
+ * @param blocksUsingDefaultSerialization - A list of the blockType of blocks which can use default serialization (they only have ConnectionPoint properties and no constructor parameters)
41
42
  * @param additionalBlockSerializers - An array of block serializers to use, beyond those for the core blocks
42
43
  */
43
44
  public constructor(blocksUsingDefaultSerialization: string[], additionalBlockSerializers: IBlockSerializerV1[]) {
44
- this._blockSerializers.set(inputBlockSerializer.className, inputBlockSerializer.serialize);
45
+ this._blockSerializers.set(inputBlockSerializer.blockType, inputBlockSerializer.serialize);
45
46
  this._blockSerializers.set(OutputBlock.ClassName, defaultBlockSerializer);
46
47
  blocksUsingDefaultSerialization.forEach((block) => {
47
48
  this._blockSerializers.set(block, defaultBlockSerializer);
48
49
  });
49
50
  additionalBlockSerializers.forEach((serializer) =>
50
- this._blockSerializers.set(serializer.className, serializer.serialize)
51
+ this._blockSerializers.set(serializer.blockType, serializer.serialize)
51
52
  );
52
53
  }
53
54
 
@@ -61,9 +62,12 @@ export class SmartFilterSerializer {
61
62
 
62
63
  const blocks = smartFilter.attachedBlocks.map((block: BaseBlock) => {
63
64
  // Serialize the block itself
64
- const serializeFn = this._blockSerializers.get(block.getClassName());
65
+ const serializeFn =
66
+ block.getClassName() === CustomShaderBlock.ClassName
67
+ ? defaultBlockSerializer
68
+ : this._blockSerializers.get(block.blockType);
65
69
  if (!serializeFn) {
66
- throw new Error(`No serializer was provided for a block of type ${block.getClassName()}`);
70
+ throw new Error(`No serializer was provided for a block of type ${block.blockType}`);
67
71
  }
68
72
  const serializedBlock: ISerializedBlockV1 = serializeFn(block);
69
73
 
@@ -102,7 +106,7 @@ export class SmartFilterSerializer {
102
106
  });
103
107
 
104
108
  return {
105
- version: 1,
109
+ formatVersion: 1,
106
110
  name: smartFilter.name,
107
111
  comments: smartFilter.comments,
108
112
  editorData: smartFilter.editorData,
@@ -0,0 +1,63 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Data Types Used For Block Serialization
4
+ * ----------------------------------------------------------------------------
5
+ */
6
+
7
+ import type { AllConnectionPointTypes, ConnectionPointValue } from "../../connection/connectionPointType";
8
+ import type { ShaderProgram } from "../../utils/shaderCodeUtils";
9
+
10
+ /**
11
+ * The V1 definition of a serialized block. A block definition is loaded by a CustomShaderBlock and defines how a
12
+ * blockType works. This should not be confused with an ISerializedBockV1, which is a serialized instance of a block in a
13
+ * serialized SmartFilter graph. It is referenced by blockType in a serialized SmartFilter.
14
+ */
15
+ export type SerializedBlockDefinitionV1 = {
16
+ /**
17
+ * The version of the block definition format (format of the serialized data, not the version of the block definition itself).
18
+ */
19
+ formatVersion: 1;
20
+
21
+ /**
22
+ * The type used to refer to the block in serialized SmartFilters and in the editor UI.
23
+ * The application doing the deserialization will use this to instantiate the correct block definition.
24
+ * Block types are expected to be unique and their behavior should be semantically equivalent across implementations
25
+ * (their results must be similar enough that the differences are not perceivable).
26
+ */
27
+ blockType: string;
28
+
29
+ /**
30
+ * The shader program for the block.
31
+ */
32
+ shaderProgram: ShaderProgram;
33
+
34
+ /**
35
+ * The input connection points of the block.
36
+ */
37
+ inputConnectionPoints: SerializedInputConnectionPointV1[];
38
+
39
+ /**
40
+ * If true, the optimizer will not attempt to optimize this block.
41
+ */
42
+ disableOptimization: boolean;
43
+ };
44
+
45
+ /**
46
+ * A V1 input connection point of a serialized block definition.
47
+ */
48
+ export type SerializedInputConnectionPointV1<U extends AllConnectionPointTypes = AllConnectionPointTypes> = {
49
+ /**
50
+ * The name of the connection point.
51
+ */
52
+ name: string;
53
+
54
+ /**
55
+ * The type of the connection point.
56
+ */
57
+ type: U;
58
+
59
+ /**
60
+ * The optional default value of the connection point.
61
+ */
62
+ defaultValue?: ConnectionPointValue<U>;
63
+ };
@@ -1,5 +1,5 @@
1
1
  import type { BaseBlock } from "../../blocks/baseBlock";
2
- import type { ISerializedBlockV1, SerializeBlockV1 } from "./serialization.types";
2
+ import type { ISerializedBlockV1, SerializeBlockV1 } from "./smartFilterSerialization.types";
3
3
 
4
4
  /**
5
5
  * The default V1 block serializer which can be used for any block that relies only on ConnectionPoints
@@ -11,7 +11,7 @@ export const defaultBlockSerializer: SerializeBlockV1 = (block: BaseBlock): ISer
11
11
  return {
12
12
  name: block.name,
13
13
  uniqueId: block.uniqueId,
14
- className: block.getClassName(),
14
+ blockType: block.blockType,
15
15
  comments: block.comments,
16
16
  data: undefined,
17
17
  };
@@ -1,2 +1,2 @@
1
1
  export * from "./defaultBlockSerializer.js";
2
- export * from "./serialization.types.js";
2
+ export * from "./smartFilterSerialization.types.js";
@@ -14,8 +14,8 @@ import type { IEditorData } from "@babylonjs/shared-ui-components/nodeGraphSyste
14
14
  * V1 Serialized Smart Filter
15
15
  */
16
16
  export type SerializedSmartFilterV1 = {
17
- /** The version of the serialized data */
18
- version: 1;
17
+ /** The format version of the serialized data (not the version of the SmartFilter itself).*/
18
+ formatVersion: 1;
19
19
 
20
20
  /** The SmartFilter name */
21
21
  name: string;
@@ -34,7 +34,8 @@ export type SerializedSmartFilterV1 = {
34
34
  };
35
35
 
36
36
  /**
37
- * V1 Serialized Block
37
+ * V1 format of a block in a serialized Smart Filter.
38
+ * Not to be confused with a SerializedBlockDefinitionV1 which serializes the definition of a CustomShaderBlock.
38
39
  */
39
40
  export interface ISerializedBlockV1 {
40
41
  /** The name of the block */
@@ -43,8 +44,8 @@ export interface ISerializedBlockV1 {
43
44
  /** The unique ID of the block - correlates with the ID in the editorData for block position, etc. */
44
45
  uniqueId: number;
45
46
 
46
- /** The class name of the block */
47
- className: string;
47
+ /** The blockType of the block - used to determine how to instantiate the block during deserialization */
48
+ blockType: string;
48
49
 
49
50
  /** The comments for the block */
50
51
  comments: Nullable<string>;
@@ -82,13 +83,13 @@ export interface ISerializedConnectionV1 {
82
83
  export type SerializeBlockV1 = (block: BaseBlock) => ISerializedBlockV1;
83
84
 
84
85
  /**
85
- * A V1 block serializer
86
+ * A V1 serializer for blocks in a SmartFilter
86
87
  */
87
88
  export interface IBlockSerializerV1 {
88
- /** The className of the block that this serializer can serialize */
89
- className: string;
89
+ /** The blockType of the block that this serializer can serialize */
90
+ blockType: string;
90
91
 
91
- /** The function that serializes the block */
92
+ /** The function that serializes the block in the Smart Filter */
92
93
  serialize: SerializeBlockV1;
93
94
  }
94
95
 
@@ -99,7 +100,7 @@ export interface IBlockSerializerV1 {
99
100
  */
100
101
 
101
102
  /**
102
- * A function that deserializes a block from a V1 serialized block object
103
+ * A function that deserializes a V1 block in a SmartFilter
103
104
  */
104
105
  export type DeserializeBlockV1 = (
105
106
  smartFilter: SmartFilter,
@@ -5,7 +5,7 @@
5
5
  * @example node buildShaders.js <shaderPath> <importPath>
6
6
  */
7
7
 
8
- import { convertShaders } from "./shaderConverter.js";
8
+ import { convertShaders } from "./convertShaderForHardcodedBlock.js";
9
9
 
10
10
  const externalArguments = process.argv.slice(2);
11
11
  if (externalArguments.length >= 2 && externalArguments[0] && externalArguments[1]) {