@onerjs/smart-filters 8.31.6 → 8.31.8
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.
- package/dist/blockFoundation/customShaderBlock.d.ts +16 -2
- package/dist/blockFoundation/customShaderBlock.d.ts.map +1 -1
- package/dist/blockFoundation/customShaderBlock.js +69 -5
- package/dist/blockFoundation/customShaderBlock.js.map +1 -1
- package/dist/blockFoundation/customShaderBlock.serializer.d.ts +22 -0
- package/dist/blockFoundation/customShaderBlock.serializer.d.ts.map +1 -0
- package/dist/blockFoundation/customShaderBlock.serializer.js +32 -0
- package/dist/blockFoundation/customShaderBlock.serializer.js.map +1 -0
- package/dist/blockFoundation/disableableShaderBlock.d.ts +5 -0
- package/dist/blockFoundation/disableableShaderBlock.d.ts.map +1 -1
- package/dist/blockFoundation/disableableShaderBlock.js +18 -11
- package/dist/blockFoundation/disableableShaderBlock.js.map +1 -1
- package/dist/editorUtils/editableInPropertyPage.d.ts +5 -0
- package/dist/editorUtils/editableInPropertyPage.d.ts.map +1 -1
- package/dist/editorUtils/editableInPropertyPage.js +11 -2
- package/dist/editorUtils/editableInPropertyPage.js.map +1 -1
- package/dist/optimization/smartFilterOptimizer.d.ts +11 -0
- package/dist/optimization/smartFilterOptimizer.d.ts.map +1 -1
- package/dist/optimization/smartFilterOptimizer.js +28 -14
- package/dist/optimization/smartFilterOptimizer.js.map +1 -1
- package/dist/serialization/importCustomBlockDefinition.js +1 -0
- package/dist/serialization/importCustomBlockDefinition.js.map +1 -1
- package/dist/serialization/smartFilterSerializer.d.ts.map +1 -1
- package/dist/serialization/smartFilterSerializer.js +6 -3
- package/dist/serialization/smartFilterSerializer.js.map +1 -1
- package/dist/serialization/v1/shaderBlockSerialization.types.d.ts +37 -0
- package/dist/serialization/v1/shaderBlockSerialization.types.d.ts.map +1 -1
- package/dist/utils/buildTools/shaderCode.types.d.ts +5 -0
- package/dist/utils/buildTools/shaderCode.types.d.ts.map +1 -1
- package/dist/utils/buildTools/shaderConverter.d.ts +10 -4
- package/dist/utils/buildTools/shaderConverter.d.ts.map +1 -1
- package/dist/utils/buildTools/shaderConverter.js +58 -2
- package/dist/utils/buildTools/shaderConverter.js.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/shaderCodeUtils.d.ts +6 -0
- package/dist/utils/shaderCodeUtils.d.ts.map +1 -1
- package/dist/utils/shaderCodeUtils.js +14 -1
- package/dist/utils/shaderCodeUtils.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/blockFoundation/customShaderBlock.serializer.ts +51 -0
- package/src/blockFoundation/customShaderBlock.ts +80 -6
- package/src/blockFoundation/disableableShaderBlock.ts +18 -9
- package/src/editorUtils/editableInPropertyPage.ts +16 -2
- package/src/optimization/smartFilterOptimizer.ts +30 -16
- package/src/serialization/importCustomBlockDefinition.ts +1 -0
- package/src/serialization/smartFilterSerializer.ts +6 -3
- package/src/serialization/v1/shaderBlockSerialization.types.ts +42 -0
- package/src/utils/buildTools/shaderCode.types.ts +65 -59
- package/src/utils/buildTools/shaderConverter.ts +96 -6
- package/src/utils/index.ts +1 -1
- package/src/utils/shaderCodeUtils.ts +16 -1
- package/src/version.ts +1 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ISerializedBlockV1, SerializeBlockV1 } from "../serialization/v1/smartFilterSerialization.types.js";
|
|
2
|
+
import type { BaseBlock } from "./baseBlock.js";
|
|
3
|
+
import { CustomShaderBlock } from "./customShaderBlock.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Data for a dynamic property on a CustomShaderBlock
|
|
7
|
+
*/
|
|
8
|
+
export type CustomShaderBlockData = {
|
|
9
|
+
/**
|
|
10
|
+
* The custom properties of the CustomShaderBlock
|
|
11
|
+
*/
|
|
12
|
+
customProperties: CustomPropertyData[];
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type CustomPropertyData = {
|
|
16
|
+
name: string;
|
|
17
|
+
value: any;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Serializes a CustomShaderBlock to V1 serialized data.
|
|
22
|
+
* @param block - The block to serialize
|
|
23
|
+
* @returns The serialized block
|
|
24
|
+
*/
|
|
25
|
+
export const CustomShaderBlockSerializer: SerializeBlockV1 = (block: BaseBlock): ISerializedBlockV1 => {
|
|
26
|
+
if (block.getClassName() !== CustomShaderBlock.ClassName) {
|
|
27
|
+
throw new Error("Was asked to serialize an unrecognized block type");
|
|
28
|
+
}
|
|
29
|
+
const customShaderBlock = block as CustomShaderBlock;
|
|
30
|
+
|
|
31
|
+
let data: CustomShaderBlockData | undefined;
|
|
32
|
+
const dynamicPropertyNames = customShaderBlock.dynamicPropertyNames;
|
|
33
|
+
if (dynamicPropertyNames.length > 0) {
|
|
34
|
+
data = {
|
|
35
|
+
customProperties: dynamicPropertyNames.map((propertyName) => ({
|
|
36
|
+
name: propertyName,
|
|
37
|
+
value: (customShaderBlock as any)[propertyName],
|
|
38
|
+
})),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
name: customShaderBlock.name,
|
|
44
|
+
uniqueId: customShaderBlock.uniqueId,
|
|
45
|
+
blockType: customShaderBlock.blockType,
|
|
46
|
+
namespace: customShaderBlock.namespace,
|
|
47
|
+
comments: customShaderBlock.comments,
|
|
48
|
+
data,
|
|
49
|
+
outputTextureOptions: customShaderBlock.outputTextureOptions,
|
|
50
|
+
};
|
|
51
|
+
};
|
|
@@ -4,12 +4,14 @@ import { ConnectionPointType, type ConnectionPointValue } from "../connection/co
|
|
|
4
4
|
import { ShaderBinding } from "../runtime/shaderRuntime.js";
|
|
5
5
|
import { CreateStrongRef } from "../runtime/strongRef.js";
|
|
6
6
|
import type { SerializedShaderBlockDefinition } from "../serialization/serializedShaderBlockDefinition.js";
|
|
7
|
-
import type { SerializedInputConnectionPointV1 } from "../serialization/v1/shaderBlockSerialization.types.js";
|
|
7
|
+
import type { SerializedInputConnectionPointV1, ConstPropertyMetadata } from "../serialization/v1/shaderBlockSerialization.types.js";
|
|
8
8
|
import type { SmartFilter } from "../smartFilter.js";
|
|
9
|
-
import type
|
|
9
|
+
import { CloneShaderProgram, type ShaderProgram } from "../utils/shaderCodeUtils.js";
|
|
10
10
|
import { ShaderBlock } from "./shaderBlock.js";
|
|
11
11
|
import type { RuntimeData } from "../connection/connectionPoint.js";
|
|
12
12
|
import type { Nullable } from "core/types.js";
|
|
13
|
+
import { EditableInPropertyPage, type IEditablePropertyOption, PropertyTypeForEdition } from "../editorUtils/editableInPropertyPage.js";
|
|
14
|
+
import type { CustomShaderBlockData } from "./customShaderBlock.serializer.js";
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
17
|
* The binding for a CustomShaderBlock
|
|
@@ -95,20 +97,33 @@ export class CustomShaderBlock extends ShaderBlock {
|
|
|
95
97
|
* @param smartFilter - The smart filter this block belongs to
|
|
96
98
|
* @param name - Defines the name of the block
|
|
97
99
|
* @param blockDefinition - The serialized block definition
|
|
100
|
+
* @param data - The data property from the serialized block, if applicable
|
|
98
101
|
* @returns The deserialized CustomShaderBlock instance
|
|
99
102
|
*/
|
|
100
|
-
public static Create(smartFilter: SmartFilter, name: string, blockDefinition: SerializedShaderBlockDefinition): CustomShaderBlock {
|
|
103
|
+
public static Create(smartFilter: SmartFilter, name: string, blockDefinition: SerializedShaderBlockDefinition, data?: any): CustomShaderBlock {
|
|
101
104
|
// When a new version of SerializedBlockDefinition is created, this function should be updated to handle the new properties.
|
|
102
105
|
|
|
103
|
-
|
|
106
|
+
const newBlock = new CustomShaderBlock(
|
|
104
107
|
smartFilter,
|
|
105
108
|
name,
|
|
106
109
|
blockDefinition.disableOptimization,
|
|
107
110
|
blockDefinition.blockType,
|
|
108
111
|
blockDefinition.namespace,
|
|
109
112
|
blockDefinition.inputConnectionPoints,
|
|
113
|
+
blockDefinition.fragmentConstProperties || [],
|
|
110
114
|
blockDefinition.shaderProgram
|
|
111
115
|
);
|
|
116
|
+
|
|
117
|
+
if (data && (data as CustomShaderBlockData).customProperties) {
|
|
118
|
+
const customProperties = (data as CustomShaderBlockData).customProperties;
|
|
119
|
+
for (const customProperty of customProperties) {
|
|
120
|
+
if (newBlock.dynamicPropertyNames.indexOf(customProperty.name) !== -1) {
|
|
121
|
+
(newBlock as any)[customProperty.name] = customProperty.value;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return newBlock;
|
|
112
127
|
}
|
|
113
128
|
|
|
114
129
|
/**
|
|
@@ -119,8 +134,16 @@ export class CustomShaderBlock extends ShaderBlock {
|
|
|
119
134
|
private readonly _shaderProgram: ShaderProgram;
|
|
120
135
|
private readonly _blockType: string;
|
|
121
136
|
private readonly _namespace: Nullable<string>;
|
|
137
|
+
private readonly _fragmentConstProperties: ConstPropertyMetadata[];
|
|
122
138
|
private _autoBoundInputs: Nullable<SerializedInputConnectionPointV1[]> = null;
|
|
123
139
|
|
|
140
|
+
/**
|
|
141
|
+
* A list of the names of the properties added to this instance of the block, for example,
|
|
142
|
+
* fragment const properties.
|
|
143
|
+
*
|
|
144
|
+
*/
|
|
145
|
+
public readonly dynamicPropertyNames: string[] = [];
|
|
146
|
+
|
|
124
147
|
/**
|
|
125
148
|
* The type of the block - used when serializing / deserializing the block, and in the editor.
|
|
126
149
|
*/
|
|
@@ -144,6 +167,7 @@ export class CustomShaderBlock extends ShaderBlock {
|
|
|
144
167
|
* @param blockType - The type of the block
|
|
145
168
|
* @param namespace - The namespace of the block
|
|
146
169
|
* @param inputConnectionPoints - The input connection points of the
|
|
170
|
+
* @param fragmentConstProperties - The define properties for the block
|
|
147
171
|
* @param shaderProgram - The shader program for the block
|
|
148
172
|
*/
|
|
149
173
|
private constructor(
|
|
@@ -153,17 +177,22 @@ export class CustomShaderBlock extends ShaderBlock {
|
|
|
153
177
|
blockType: string,
|
|
154
178
|
namespace: Nullable<string>,
|
|
155
179
|
inputConnectionPoints: SerializedInputConnectionPointV1[],
|
|
180
|
+
fragmentConstProperties: ConstPropertyMetadata[],
|
|
156
181
|
shaderProgram: ShaderProgram
|
|
157
182
|
) {
|
|
158
183
|
super(smartFilter, name, disableOptimization);
|
|
159
184
|
this._blockType = blockType;
|
|
160
185
|
this._namespace = namespace;
|
|
186
|
+
this._shaderProgram = shaderProgram;
|
|
187
|
+
this._fragmentConstProperties = fragmentConstProperties;
|
|
161
188
|
|
|
162
189
|
for (const input of inputConnectionPoints) {
|
|
163
190
|
this._registerSerializedInputConnectionPointV1(input);
|
|
164
191
|
}
|
|
165
192
|
|
|
166
|
-
|
|
193
|
+
for (const constProperty of fragmentConstProperties) {
|
|
194
|
+
this._createConstProperty(constProperty);
|
|
195
|
+
}
|
|
167
196
|
}
|
|
168
197
|
|
|
169
198
|
/**
|
|
@@ -171,7 +200,52 @@ export class CustomShaderBlock extends ShaderBlock {
|
|
|
171
200
|
* @returns The shader program to use to render the block
|
|
172
201
|
*/
|
|
173
202
|
public override getShaderProgram() {
|
|
174
|
-
|
|
203
|
+
if (this._fragmentConstProperties.length === 0) {
|
|
204
|
+
return this._shaderProgram;
|
|
205
|
+
} else {
|
|
206
|
+
// Make a copy of the shader program and append const properties to the fragment shader consts
|
|
207
|
+
const shaderProgramForThisInstance = CloneShaderProgram(this._shaderProgram);
|
|
208
|
+
shaderProgramForThisInstance.fragment.constPerInstance =
|
|
209
|
+
this._fragmentConstProperties
|
|
210
|
+
.map((property) => {
|
|
211
|
+
switch (property.type) {
|
|
212
|
+
case "float": {
|
|
213
|
+
const value = (this as any)[property.friendlyName] as number;
|
|
214
|
+
const valueStr = Number.isInteger(value) ? value.toString() + "." : value.toString();
|
|
215
|
+
return `const float ${property.name} = ${valueStr};`;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
})
|
|
219
|
+
.join("\n") + "\n";
|
|
220
|
+
|
|
221
|
+
return shaderProgramForThisInstance;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Creates a dynamic property for the supplied const property with EditableInPropertyPage decorator.
|
|
227
|
+
* @param constProperty - The const property metadata
|
|
228
|
+
*/
|
|
229
|
+
private _createConstProperty(constProperty: ConstPropertyMetadata): void {
|
|
230
|
+
// Create the property and assign the default value
|
|
231
|
+
(this as any)[constProperty.friendlyName] = constProperty.defaultValue;
|
|
232
|
+
this.dynamicPropertyNames.push(constProperty.friendlyName);
|
|
233
|
+
|
|
234
|
+
// Use the EditableInPropertyPage decorator to make the property editable in the Smart Filters Editor
|
|
235
|
+
const editablePropertyOptions: IEditablePropertyOption = {
|
|
236
|
+
notifiers: { rebuild: true },
|
|
237
|
+
blockType: this._blockType,
|
|
238
|
+
};
|
|
239
|
+
if (constProperty.options) {
|
|
240
|
+
editablePropertyOptions.options = Object.keys(constProperty.options).map((key) => {
|
|
241
|
+
return { label: key, value: (constProperty.options as any)[key] };
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const propertyType: PropertyTypeForEdition = constProperty.options ? PropertyTypeForEdition.List : PropertyTypeForEdition.Float;
|
|
246
|
+
|
|
247
|
+
const decoratorApplier = EditableInPropertyPage(constProperty.friendlyName, propertyType, "PROPERTIES", editablePropertyOptions);
|
|
248
|
+
decoratorApplier(this, constProperty.friendlyName);
|
|
175
249
|
}
|
|
176
250
|
|
|
177
251
|
/**
|
|
@@ -65,27 +65,36 @@ export abstract class DisableableShaderBlock extends ShaderBlock implements IDis
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
|
-
*
|
|
69
|
-
* @
|
|
70
|
-
* @param name - Defines the name of the block
|
|
71
|
-
* @param disableOptimization - Defines if the block should not be optimized (default: false)
|
|
72
|
-
* @param disableStrategy - Defines the strategy to use for making this block disableable (default: BlockDisableStrategy.AutoSample)
|
|
68
|
+
* Gets the shader program to use to render the block.
|
|
69
|
+
* @returns The shader program to use to render the block
|
|
73
70
|
*/
|
|
74
|
-
|
|
75
|
-
super(
|
|
76
|
-
this.blockDisableStrategy = disableStrategy;
|
|
71
|
+
public override getShaderProgram() {
|
|
72
|
+
const shaderProgram = super.getShaderProgram();
|
|
77
73
|
|
|
78
74
|
// If we haven't already modified the shader code for this block type, do so now
|
|
79
75
|
if (!this._hasModifiedShaderCode) {
|
|
80
76
|
this._hasModifiedShaderCode = true;
|
|
81
77
|
|
|
82
78
|
// Apply the disable strategy
|
|
83
|
-
const shaderProgram = this.getShaderProgram();
|
|
84
79
|
switch (this.blockDisableStrategy) {
|
|
85
80
|
case BlockDisableStrategy.AutoSample:
|
|
86
81
|
InjectAutoSampleDisableCode(shaderProgram);
|
|
87
82
|
break;
|
|
88
83
|
}
|
|
89
84
|
}
|
|
85
|
+
|
|
86
|
+
return shaderProgram;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Instantiates a new block.
|
|
91
|
+
* @param smartFilter - Defines the smart filter the block belongs to
|
|
92
|
+
* @param name - Defines the name of the block
|
|
93
|
+
* @param disableOptimization - Defines if the block should not be optimized (default: false)
|
|
94
|
+
* @param disableStrategy - Defines the strategy to use for making this block disableable (default: BlockDisableStrategy.AutoSample)
|
|
95
|
+
*/
|
|
96
|
+
constructor(smartFilter: SmartFilter, name: string, disableOptimization = false, disableStrategy = BlockDisableStrategy.AutoSample) {
|
|
97
|
+
super(smartFilter, name, disableOptimization);
|
|
98
|
+
this.blockDisableStrategy = disableStrategy;
|
|
90
99
|
}
|
|
91
100
|
}
|
|
@@ -53,6 +53,11 @@ export interface IEditablePropertyOption {
|
|
|
53
53
|
valuesAreStrings?: boolean;
|
|
54
54
|
/** If supplied, the sub property to read/write */
|
|
55
55
|
subPropertyName?: string;
|
|
56
|
+
/**
|
|
57
|
+
* If supplied, scope this to a specific block type - useful for the
|
|
58
|
+
* CustomShaderBlock where multiple block types are implemented with the same class
|
|
59
|
+
*/
|
|
60
|
+
blockType?: string;
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
/**
|
|
@@ -94,13 +99,22 @@ export function EditableInPropertyPage(
|
|
|
94
99
|
target._propStore = propStore;
|
|
95
100
|
}
|
|
96
101
|
|
|
97
|
-
|
|
102
|
+
const propToAdd: IPropertyDescriptionForEdition = {
|
|
98
103
|
propertyName: propertyKey,
|
|
99
104
|
displayName: displayName,
|
|
100
105
|
type: propertyType,
|
|
101
106
|
groupName: groupName,
|
|
102
107
|
options: options ?? {},
|
|
103
108
|
className: target.constructor.name,
|
|
104
|
-
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// If the property already exists, overwrite it, otherwise add it
|
|
112
|
+
// Note: It may have been redefined since the application started
|
|
113
|
+
const existingIndex = propStore.findIndex((p) => p.propertyName === propertyKey && p.className === target.constructor.name && options?.blockType === p.options?.blockType);
|
|
114
|
+
if (existingIndex !== -1) {
|
|
115
|
+
propStore[existingIndex] = propToAdd;
|
|
116
|
+
} else {
|
|
117
|
+
propStore.push(propToAdd);
|
|
118
|
+
}
|
|
105
119
|
};
|
|
106
120
|
}
|
|
@@ -243,8 +243,8 @@ export class SmartFilterOptimizer {
|
|
|
243
243
|
return newVarName;
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
-
private _processDefines(block: ShaderBlock, renameWork: RenameWork) {
|
|
247
|
-
const defines =
|
|
246
|
+
private _processDefines(block: ShaderBlock, shaderProgram: ShaderProgram, renameWork: RenameWork) {
|
|
247
|
+
const defines = shaderProgram.fragment.defines;
|
|
248
248
|
if (!defines) {
|
|
249
249
|
return;
|
|
250
250
|
}
|
|
@@ -292,11 +292,12 @@ export class SmartFilterOptimizer {
|
|
|
292
292
|
* folded into the final optimized block.
|
|
293
293
|
* NOTE: so this function can know about the uniforms to test for them, it must be called after _processVariables.
|
|
294
294
|
* @param block - The block we are processing
|
|
295
|
+
* @param shaderProgram - The shader program associated with the block
|
|
295
296
|
* @param renameWork - The list of rename work to add to as needed
|
|
296
297
|
* @param samplerList - The list of sampler names
|
|
297
298
|
*/
|
|
298
|
-
private _processHelperFunctions(block: ShaderBlock, renameWork: RenameWork, samplerList: string[]): void {
|
|
299
|
-
const functions =
|
|
299
|
+
private _processHelperFunctions(block: ShaderBlock, shaderProgram: ShaderProgram, renameWork: RenameWork, samplerList: string[]): void {
|
|
300
|
+
const functions = shaderProgram.fragment.functions;
|
|
300
301
|
|
|
301
302
|
if (functions.length === 1) {
|
|
302
303
|
// There's only the main function, so we don't need to do anything
|
|
@@ -306,7 +307,7 @@ export class SmartFilterOptimizer {
|
|
|
306
307
|
for (const func of functions) {
|
|
307
308
|
let funcName = func.name;
|
|
308
309
|
|
|
309
|
-
if (funcName ===
|
|
310
|
+
if (funcName === shaderProgram.fragment.mainFunctionName) {
|
|
310
311
|
continue;
|
|
311
312
|
}
|
|
312
313
|
|
|
@@ -381,19 +382,29 @@ export class SmartFilterOptimizer {
|
|
|
381
382
|
}
|
|
382
383
|
}
|
|
383
384
|
|
|
385
|
+
/**
|
|
386
|
+
* Processes either consts or uniforms. Handles capturing the rename work needed, updating the sampler list, and
|
|
387
|
+
* accounting for single instance situations (where a const or uniform is shared across all instances of this block).
|
|
388
|
+
* @param block - The block to work on
|
|
389
|
+
* @param renameWork - The RenameWork list to update
|
|
390
|
+
* @param varDecl - Which type of variable we're working with
|
|
391
|
+
* @param declarations - The declarations of those variables from the shader
|
|
392
|
+
* @param sharedByAllInstances - If this should be treated as a shared value across all instances of this shader block
|
|
393
|
+
* @returns The list of samplers
|
|
394
|
+
*/
|
|
384
395
|
private _processVariables(
|
|
385
396
|
block: ShaderBlock,
|
|
386
397
|
renameWork: RenameWork,
|
|
387
398
|
varDecl: "const" | "uniform",
|
|
388
|
-
declarations
|
|
389
|
-
|
|
390
|
-
forceSingleInstance = false
|
|
399
|
+
declarations: string | undefined,
|
|
400
|
+
sharedByAllInstances: boolean
|
|
391
401
|
): Array<string> {
|
|
392
402
|
if (!declarations) {
|
|
393
403
|
return [];
|
|
394
404
|
}
|
|
395
405
|
|
|
396
406
|
let rex = `${varDecl}\\s+(\\S+)\\s+${DecorateChar}(\\w+)${DecorateChar}\\s*`;
|
|
407
|
+
const hasValue = varDecl !== "uniform";
|
|
397
408
|
if (hasValue) {
|
|
398
409
|
rex += "=\\s*(.+);";
|
|
399
410
|
} else {
|
|
@@ -405,7 +416,6 @@ export class SmartFilterOptimizer {
|
|
|
405
416
|
|
|
406
417
|
let match = rx.exec(declarations);
|
|
407
418
|
while (match !== null) {
|
|
408
|
-
const singleInstance = forceSingleInstance || varDecl === "const";
|
|
409
419
|
const varType = match[1]!;
|
|
410
420
|
const varName = match[2]!;
|
|
411
421
|
const varValue = hasValue ? match[3]! : null;
|
|
@@ -416,7 +426,7 @@ export class SmartFilterOptimizer {
|
|
|
416
426
|
samplerList.push(DecorateSymbol(varName));
|
|
417
427
|
} else {
|
|
418
428
|
const existingRemapped = this._remappedSymbols.find((s) => s.type === varDecl && s.name === varName && s.owners[0] && s.owners[0].blockType === block.blockType);
|
|
419
|
-
if (existingRemapped &&
|
|
429
|
+
if (existingRemapped && sharedByAllInstances) {
|
|
420
430
|
newVarName = existingRemapped.remappedName;
|
|
421
431
|
if (varDecl === "uniform") {
|
|
422
432
|
existingRemapped.owners.push(block);
|
|
@@ -486,13 +496,13 @@ export class SmartFilterOptimizer {
|
|
|
486
496
|
return UndecorateSymbol(newSamplerName);
|
|
487
497
|
}
|
|
488
498
|
|
|
489
|
-
private _canBeOptimized(block: BaseBlock): boolean {
|
|
499
|
+
private _canBeOptimized(block: BaseBlock, shaderProgram: ShaderProgram): boolean {
|
|
490
500
|
if (block.disableOptimization) {
|
|
491
501
|
return false;
|
|
492
502
|
}
|
|
493
503
|
|
|
494
504
|
if (block instanceof ShaderBlock) {
|
|
495
|
-
if (
|
|
505
|
+
if (shaderProgram.vertex !== this._vertexShaderCode) {
|
|
496
506
|
return false;
|
|
497
507
|
}
|
|
498
508
|
|
|
@@ -517,6 +527,7 @@ export class SmartFilterOptimizer {
|
|
|
517
527
|
this._currentOutputTextureOptions = block.outputTextureOptions;
|
|
518
528
|
}
|
|
519
529
|
|
|
530
|
+
// Sometimes getShaderProgram() does work, so only grab it once for efficiency
|
|
520
531
|
const shaderProgram = block.getShaderProgram();
|
|
521
532
|
if (!shaderProgram) {
|
|
522
533
|
throw new Error(`Shader program not found for block "${block.name}"!`);
|
|
@@ -546,22 +557,25 @@ export class SmartFilterOptimizer {
|
|
|
546
557
|
}
|
|
547
558
|
|
|
548
559
|
// Processes the defines to make them unique
|
|
549
|
-
this._processDefines(block, renameWork);
|
|
560
|
+
this._processDefines(block, shaderProgram, renameWork);
|
|
550
561
|
|
|
551
562
|
// Processes the constants to make them unique
|
|
552
563
|
this._processVariables(block, renameWork, "const", shaderProgram.fragment.const, true);
|
|
553
564
|
|
|
565
|
+
// Processes the per-instance constants
|
|
566
|
+
this._processVariables(block, renameWork, "const", shaderProgram.fragment.constPerInstance, false);
|
|
567
|
+
|
|
554
568
|
// Processes the uniform inputs to make them unique. Also extract the list of samplers
|
|
555
569
|
let samplerList: string[] = [];
|
|
556
570
|
samplerList = this._processVariables(block, renameWork, "uniform", shaderProgram.fragment.uniform, false);
|
|
557
571
|
|
|
558
572
|
let additionalSamplers = [];
|
|
559
|
-
additionalSamplers = this._processVariables(block, renameWork, "uniform", shaderProgram.fragment.uniformSingle,
|
|
573
|
+
additionalSamplers = this._processVariables(block, renameWork, "uniform", shaderProgram.fragment.uniformSingle, true);
|
|
560
574
|
|
|
561
575
|
samplerList.push(...additionalSamplers);
|
|
562
576
|
|
|
563
577
|
// Processes the functions other than the main function - must be done after _processVariables()
|
|
564
|
-
this._processHelperFunctions(block, renameWork, samplerList);
|
|
578
|
+
this._processHelperFunctions(block, shaderProgram, renameWork, samplerList);
|
|
565
579
|
|
|
566
580
|
// Processes the texture inputs
|
|
567
581
|
for (const sampler of samplerList) {
|
|
@@ -589,7 +603,7 @@ export class SmartFilterOptimizer {
|
|
|
589
603
|
if (IsTextureInputBlock(parentBlock)) {
|
|
590
604
|
// input is connected to an InputBlock of type "Texture": we must directly sample a texture
|
|
591
605
|
this._processSampleTexture(block, renameWork, samplerName, samplers, parentBlock);
|
|
592
|
-
} else if (this._forceUnoptimized || !this._canBeOptimized(parentBlock)) {
|
|
606
|
+
} else if (this._forceUnoptimized || !this._canBeOptimized(parentBlock, shaderProgram)) {
|
|
593
607
|
// the block connected to this input cannot be optimized: we must directly sample its output texture
|
|
594
608
|
const uniqueSamplerName = this._processSampleTexture(block, renameWork, samplerName, samplers);
|
|
595
609
|
let stackItem = this._blockToStackItem.get(parentBlock);
|
|
@@ -81,6 +81,7 @@ function ImportAnnotatedGlsl(fragmentShader: string): SerializedShaderBlockDefin
|
|
|
81
81
|
fragment: fragmentShaderInfo.shaderCode,
|
|
82
82
|
},
|
|
83
83
|
inputConnectionPoints,
|
|
84
|
+
fragmentConstProperties: fragmentShaderInfo.fragmentConstProperties,
|
|
84
85
|
disableOptimization: !!fragmentShaderInfo.disableOptimization,
|
|
85
86
|
};
|
|
86
87
|
}
|
|
@@ -7,6 +7,7 @@ import { OutputBlock } from "../blockFoundation/outputBlock.js";
|
|
|
7
7
|
import type { IBlockSerializerV1, ISerializedBlockV1, ISerializedConnectionV1, SerializeBlockV1, SerializedSmartFilterV1 } from "./v1/smartFilterSerialization.types.js";
|
|
8
8
|
import { CustomShaderBlock } from "../blockFoundation/customShaderBlock.js";
|
|
9
9
|
import { CustomAggregateBlock } from "../blockFoundation/customAggregateBlock.js";
|
|
10
|
+
import { CustomShaderBlockSerializer } from "../blockFoundation/customShaderBlock.serializer.js";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Determines if two serialized connection points are equivalent to each other
|
|
@@ -54,9 +55,11 @@ export class SmartFilterSerializer {
|
|
|
54
55
|
// Serialize the block itself
|
|
55
56
|
const blockClassName = block.getClassName();
|
|
56
57
|
const serializeFn =
|
|
57
|
-
blockClassName === CustomShaderBlock.ClassName
|
|
58
|
-
?
|
|
59
|
-
:
|
|
58
|
+
blockClassName === CustomShaderBlock.ClassName
|
|
59
|
+
? CustomShaderBlockSerializer
|
|
60
|
+
: blockClassName === CustomAggregateBlock.ClassName
|
|
61
|
+
? DefaultBlockSerializer
|
|
62
|
+
: this._blockSerializers.get(block.blockType);
|
|
60
63
|
if (!serializeFn) {
|
|
61
64
|
throw new Error(`No serializer was provided for a block of type ${block.blockType}`);
|
|
62
65
|
}
|
|
@@ -8,6 +8,43 @@ import type { Nullable } from "core/types.js";
|
|
|
8
8
|
import type { AllConnectionPointTypes, ConnectionPointValue } from "../../connection/connectionPointType.js";
|
|
9
9
|
import type { ShaderProgram } from "../../utils/shaderCodeUtils.js";
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Description of a const property exposed by a shader block.
|
|
13
|
+
*/
|
|
14
|
+
type ConstPropertyMetadataBase = {
|
|
15
|
+
/**
|
|
16
|
+
* The name of the const in the shader code
|
|
17
|
+
*/
|
|
18
|
+
name: string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A friendly name for the property to be displayed in the Smart Filters Editor UI.
|
|
22
|
+
* This is the undecorated name of the const in the shader code.
|
|
23
|
+
*/
|
|
24
|
+
friendlyName: string;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The type of the property
|
|
28
|
+
*/
|
|
29
|
+
type: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
type ConstPropertyMetadataFloat = ConstPropertyMetadataBase & {
|
|
33
|
+
type: "float";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The default value of the property
|
|
37
|
+
*/
|
|
38
|
+
defaultValue: number;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Optional mapping of values to strings to be displayed in the Smart Filters Editor UI for this property.
|
|
42
|
+
*/
|
|
43
|
+
options?: { [key: string]: number };
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export type ConstPropertyMetadata = ConstPropertyMetadataFloat;
|
|
47
|
+
|
|
11
48
|
/**
|
|
12
49
|
* The V1 definition of a serialized shader block. This block definition is loaded by a CustomShaderBlock and defines how a
|
|
13
50
|
* blockType works. This should not be confused with an ISerializedBockV1, which is a serialized instance of a block in a
|
|
@@ -48,6 +85,11 @@ export type SerializedShaderBlockDefinitionV1 = {
|
|
|
48
85
|
*/
|
|
49
86
|
inputConnectionPoints: SerializedInputConnectionPointV1[];
|
|
50
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Properties which map to consts in the fragment shader.
|
|
90
|
+
*/
|
|
91
|
+
fragmentConstProperties?: ConstPropertyMetadata[];
|
|
92
|
+
|
|
51
93
|
/**
|
|
52
94
|
* If true, the optimizer will not attempt to optimize this block.
|
|
53
95
|
*/
|
|
@@ -1,59 +1,65 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Describes a shader function.
|
|
3
|
-
*/
|
|
4
|
-
export type ShaderFunction = {
|
|
5
|
-
/**
|
|
6
|
-
* The name of the function.
|
|
7
|
-
*/
|
|
8
|
-
name: string;
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* The code of the function.
|
|
12
|
-
*/
|
|
13
|
-
code: string;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* The parameters of the function.
|
|
17
|
-
*/
|
|
18
|
-
params?: string;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Describes a shader code.
|
|
23
|
-
*/
|
|
24
|
-
export type ShaderCode = {
|
|
25
|
-
/**
|
|
26
|
-
* The declaration of the const variables.
|
|
27
|
-
*/
|
|
28
|
-
const?: string;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* The declaration of the
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Describes a shader function.
|
|
3
|
+
*/
|
|
4
|
+
export type ShaderFunction = {
|
|
5
|
+
/**
|
|
6
|
+
* The name of the function.
|
|
7
|
+
*/
|
|
8
|
+
name: string;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The code of the function.
|
|
12
|
+
*/
|
|
13
|
+
code: string;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The parameters of the function.
|
|
17
|
+
*/
|
|
18
|
+
params?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Describes a shader code.
|
|
23
|
+
*/
|
|
24
|
+
export type ShaderCode = {
|
|
25
|
+
/**
|
|
26
|
+
* The declaration of the const variables.
|
|
27
|
+
*/
|
|
28
|
+
const?: string;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The declaration of const variables which can be modified by each instance of the block using
|
|
32
|
+
* this ShaderCode. The optimizer will not consolidate when there are multiple instances of the same block.
|
|
33
|
+
*/
|
|
34
|
+
constPerInstance?: string;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The declaration of the uniform variables.
|
|
38
|
+
*/
|
|
39
|
+
uniform?: string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The declaration of the uniform variables that should be common for all ShaderBlock instances using this shader code.
|
|
43
|
+
*/
|
|
44
|
+
uniformSingle?: string;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The name of the main function.
|
|
48
|
+
*/
|
|
49
|
+
mainFunctionName: string;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The name of the input texture which is passed through if the block is disabled.
|
|
53
|
+
*/
|
|
54
|
+
mainInputTexture?: string;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The list of functions used in the shader.
|
|
58
|
+
*/
|
|
59
|
+
functions: ShaderFunction[];
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The declaration of define statements.
|
|
63
|
+
*/
|
|
64
|
+
defines?: string[];
|
|
65
|
+
};
|