@babylonjs/smart-filters 0.7.12-alpha → 0.7.14-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.
- package/dist/command/commandBufferDebugger.d.ts.map +1 -1
- package/dist/command/commandBufferDebugger.js +4 -3
- package/dist/command/commandBufferDebugger.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/optimization/dependencyGraph.d.ts.map +1 -1
- package/dist/optimization/dependencyGraph.js +2 -1
- package/dist/optimization/dependencyGraph.js.map +1 -1
- package/dist/optimization/smartFilterOptimizer.d.ts.map +1 -1
- package/dist/optimization/smartFilterOptimizer.js +7 -6
- package/dist/optimization/smartFilterOptimizer.js.map +1 -1
- package/dist/serialization/importCustomBlockDefinition.js +1 -25
- package/dist/serialization/importCustomBlockDefinition.js.map +1 -1
- package/dist/utils/buildTools/buildShaders.js +1 -1
- package/dist/utils/buildTools/buildShaders.js.map +1 -1
- package/dist/utils/buildTools/convertGlslIntoBlock.d.ts +7 -0
- package/dist/utils/buildTools/convertGlslIntoBlock.d.ts.map +1 -0
- package/dist/utils/buildTools/convertGlslIntoBlock.js +217 -0
- package/dist/utils/buildTools/convertGlslIntoBlock.js.map +1 -0
- package/dist/utils/buildTools/convertGlslIntoShaderProgram.d.ts +26 -0
- package/dist/utils/buildTools/convertGlslIntoShaderProgram.d.ts.map +1 -0
- package/dist/utils/buildTools/{convertShaderForHardcodedBlock.js → convertGlslIntoShaderProgram.js} +45 -31
- package/dist/utils/buildTools/convertGlslIntoShaderProgram.js.map +1 -0
- package/dist/utils/buildTools/convertShaders.d.ts +13 -0
- package/dist/utils/buildTools/convertShaders.d.ts.map +1 -0
- package/dist/utils/buildTools/convertShaders.js +38 -0
- package/dist/utils/buildTools/convertShaders.js.map +1 -0
- package/dist/utils/buildTools/determineVersion.d.ts.map +1 -1
- package/dist/utils/buildTools/determineVersion.js.map +1 -1
- package/dist/utils/buildTools/shaderConverter.d.ts +2 -1
- package/dist/utils/buildTools/shaderConverter.d.ts.map +1 -1
- package/dist/utils/buildTools/shaderConverter.js +32 -6
- package/dist/utils/buildTools/shaderConverter.js.map +1 -1
- package/dist/utils/buildTools/versionUp.js +1 -0
- package/dist/utils/buildTools/versionUp.js.map +1 -1
- package/dist/utils/buildTools/watchShaders.js +2 -2
- package/dist/utils/buildTools/watchShaders.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/readme.md +1 -171
- package/src/command/commandBufferDebugger.ts +4 -3
- package/src/index.ts +3 -0
- package/src/optimization/dependencyGraph.ts +3 -1
- package/src/optimization/smartFilterOptimizer.ts +7 -6
- package/src/serialization/importCustomBlockDefinition.ts +1 -26
- package/src/utils/buildTools/buildShaders.ts +1 -1
- package/src/utils/buildTools/convertGlslIntoBlock.ts +251 -0
- package/src/utils/buildTools/{convertShaderForHardcodedBlock.ts → convertGlslIntoShaderProgram.ts} +58 -36
- package/src/utils/buildTools/convertShaders.ts +43 -0
- package/src/utils/buildTools/determineVersion.ts +1 -0
- package/src/utils/buildTools/shaderConverter.ts +34 -7
- package/src/utils/buildTools/versionUp.ts +1 -0
- package/src/utils/buildTools/watchShaders.ts +2 -2
- package/src/version.ts +1 -1
- package/dist/utils/buildTools/convertShaderForHardcodedBlock.d.ts +0 -13
- package/dist/utils/buildTools/convertShaderForHardcodedBlock.d.ts.map +0 -1
- package/dist/utils/buildTools/convertShaderForHardcodedBlock.js.map +0 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Logger } from "@babylonjs/core/Misc/logger.js";
|
|
1
2
|
import type { CommandBuffer } from "./commandBuffer";
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -5,9 +6,9 @@ import type { CommandBuffer } from "./commandBuffer";
|
|
|
5
6
|
* @param commandBuffer - The command buffer to log
|
|
6
7
|
*/
|
|
7
8
|
export function logCommands(commandBuffer: Readonly<CommandBuffer>) {
|
|
8
|
-
|
|
9
|
+
Logger.Log("----- Command buffer commands -----");
|
|
9
10
|
commandBuffer.visitCommands((command) => {
|
|
10
|
-
|
|
11
|
+
Logger.Log(` Owner: ${command.owner.blockType} (${command.owner.name}) - Command: ${command.name}`);
|
|
11
12
|
});
|
|
12
|
-
|
|
13
|
+
Logger.Log("-----------------------------------");
|
|
13
14
|
}
|
package/src/index.ts
CHANGED
|
@@ -10,3 +10,6 @@ export * from "./utils/index.js";
|
|
|
10
10
|
export { type IDisposable } from "./IDisposable.js";
|
|
11
11
|
export { SmartFilter, type InitializationData } from "./smartFilter.js";
|
|
12
12
|
export * from "./version.js";
|
|
13
|
+
|
|
14
|
+
// So that users of the Smart Filters core can easily modify the logger settings (e.g. to change the logging level)
|
|
15
|
+
export { Logger } from "@babylonjs/core/Misc/logger.js";
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Logger } from "@babylonjs/core/Misc/logger.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Implementation of a dependency graph.
|
|
3
5
|
*/
|
|
@@ -87,7 +89,7 @@ export class DependencyGraph<T> {
|
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
if (this._list.size > 0) {
|
|
90
|
-
|
|
92
|
+
Logger.Error(JSON.stringify(this._list));
|
|
91
93
|
throw new Error("Circular dependency detected!");
|
|
92
94
|
}
|
|
93
95
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Nullable } from "@babylonjs/core/types";
|
|
2
|
+
import { Logger } from "@babylonjs/core/Misc/logger.js";
|
|
2
3
|
|
|
3
4
|
import type { ConnectionPoint } from "../connection/connectionPoint";
|
|
4
5
|
import type { ShaderBinding } from "../runtime/shaderRuntime";
|
|
@@ -690,12 +691,12 @@ export class SmartFilterOptimizer {
|
|
|
690
691
|
code = code!.replace(/\r/g, "");
|
|
691
692
|
code = code!.replace(/\n(\n)*/g, "\n");
|
|
692
693
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
694
|
+
Logger.Log(`=================== BLOCK (forceUnoptimized=${this._forceUnoptimized}) ===================`);
|
|
695
|
+
Logger.Log(codeUniforms);
|
|
696
|
+
Logger.Log(codeConsts);
|
|
697
|
+
Logger.Log(code);
|
|
698
|
+
Logger.Log(`remappedSymbols=${this._remappedSymbols}`);
|
|
699
|
+
Logger.Log(`samplers=${samplers}`);
|
|
699
700
|
}
|
|
700
701
|
|
|
701
702
|
optimizedBlock.setShaderProgram({
|
|
@@ -54,35 +54,10 @@ function importAnnotatedGlsl(fragmentShader: string): SerializedShaderBlockDefin
|
|
|
54
54
|
// Calculate the input connection points
|
|
55
55
|
const inputConnectionPoints: SerializedInputConnectionPointV1[] = [];
|
|
56
56
|
for (const uniform of fragmentShaderInfo.uniforms) {
|
|
57
|
-
// Convert to ConnectionPointType
|
|
58
|
-
let type: ConnectionPointType;
|
|
59
|
-
switch (uniform.type) {
|
|
60
|
-
case "float":
|
|
61
|
-
type = ConnectionPointType.Float;
|
|
62
|
-
break;
|
|
63
|
-
case "sampler2D":
|
|
64
|
-
type = ConnectionPointType.Texture;
|
|
65
|
-
break;
|
|
66
|
-
case "vec3":
|
|
67
|
-
type = ConnectionPointType.Color3;
|
|
68
|
-
break;
|
|
69
|
-
case "vec4":
|
|
70
|
-
type = ConnectionPointType.Color4;
|
|
71
|
-
break;
|
|
72
|
-
case "bool":
|
|
73
|
-
type = ConnectionPointType.Boolean;
|
|
74
|
-
break;
|
|
75
|
-
case "vec2":
|
|
76
|
-
type = ConnectionPointType.Vector2;
|
|
77
|
-
break;
|
|
78
|
-
default:
|
|
79
|
-
throw new Error(`Unsupported uniform type: '${uniform.type}'`);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
57
|
// Add to input connection point list
|
|
83
58
|
const inputConnectionPoint: SerializedInputConnectionPointV1 = {
|
|
84
59
|
name: uniform.name,
|
|
85
|
-
type,
|
|
60
|
+
type: uniform.type,
|
|
86
61
|
autoBind: uniform.properties?.autoBind as InputAutoBindV1,
|
|
87
62
|
};
|
|
88
63
|
if (inputConnectionPoint.type !== ConnectionPointType.Texture && uniform.properties?.default !== undefined) {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @example node buildShaders.js <shaderPath> <importPath>
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { convertShaders } from "./
|
|
8
|
+
import { convertShaders } from "./convertShaders.js";
|
|
9
9
|
|
|
10
10
|
const externalArguments = process.argv.slice(2);
|
|
11
11
|
if (externalArguments.length >= 2 && externalArguments[0] && externalArguments[1]) {
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import { extractShaderProgramFromGlsl } from "./convertGlslIntoShaderProgram.js";
|
|
3
|
+
import { ConnectionPointType } from "../../connection/connectionPointType.js";
|
|
4
|
+
|
|
5
|
+
const SHADER_PROGRAM = "@SHADER_PROGRAM@";
|
|
6
|
+
const BLOCK_NAME = "@BLOCK_NAME@";
|
|
7
|
+
const NAMESPACE = "@NAMESPACE@";
|
|
8
|
+
const SHADER_BINDING_PRIVATE_VARIABLES = "@SHADER_BINDING_PRIVATE_VARIABLES@";
|
|
9
|
+
const CAMEL_CASE_UNIFORM = "@CAMEL_CASE_UNIFORM@";
|
|
10
|
+
const CONNECTION_POINT_TYPE = "@CONNECTION_POINT_TYPE@";
|
|
11
|
+
const SHADER_BINDING_CTOR_DOCSTRING_PARAMS = "@SHADER_BINDING_CTOR_DOCSTRING_PARAMS@";
|
|
12
|
+
const SHADER_BINDING_CTOR_PARAMS = "@SHADER_CTOR_PARAMS@";
|
|
13
|
+
const SHADER_BINDING_CTOR = "@SHADER_BINDING_CTOR@";
|
|
14
|
+
const SHADER_BINDING_BIND = "@SHADER_BINDING_BIND@";
|
|
15
|
+
const BLOCK_INPUT_PROPERTIES = "@BLOCK_INPUT_PROPERTIES@";
|
|
16
|
+
const BLOCK_GET_SHADER_BINDING_VARS = "@BLOCK_SHADER_BINDING_BIND_VARS@";
|
|
17
|
+
const BLOCK_GET_SHADER_PARAM_LIST = "@BLOCK_GET_SHADER_PARAM_LIST@";
|
|
18
|
+
const EFFECT_SETTER = "@EFFECT_SETTER@";
|
|
19
|
+
|
|
20
|
+
const ShaderBindingPrivateVariablesTemplate = ` private readonly _${CAMEL_CASE_UNIFORM}: RuntimeData<ConnectionPointType.${CONNECTION_POINT_TYPE}>;`;
|
|
21
|
+
const ShaderBindingCtorDocstringParams = ` * @param ${CAMEL_CASE_UNIFORM} - The ${CAMEL_CASE_UNIFORM} runtime value`;
|
|
22
|
+
const ShaderBindingCtorParams = ` ${CAMEL_CASE_UNIFORM}: RuntimeData<ConnectionPointType.${CONNECTION_POINT_TYPE}>`;
|
|
23
|
+
const ShaderBindingCtor = ` this._${CAMEL_CASE_UNIFORM} = ${CAMEL_CASE_UNIFORM};`;
|
|
24
|
+
const ShaderBindingBind = ` effect.${EFFECT_SETTER}(this.getRemappedName(uniforms.${CAMEL_CASE_UNIFORM}), this._${CAMEL_CASE_UNIFORM}.value);`;
|
|
25
|
+
|
|
26
|
+
const BlockInputProperties = ` /**
|
|
27
|
+
* The ${CAMEL_CASE_UNIFORM} connection point.
|
|
28
|
+
*/
|
|
29
|
+
public readonly ${CAMEL_CASE_UNIFORM} = this._registerInput(uniforms.${CAMEL_CASE_UNIFORM}, ConnectionPointType.${CONNECTION_POINT_TYPE});
|
|
30
|
+
`;
|
|
31
|
+
const BlockGetShaderBindingVars = ` const ${CAMEL_CASE_UNIFORM} = this._confirmRuntimeDataSupplied(this.${CAMEL_CASE_UNIFORM});`;
|
|
32
|
+
|
|
33
|
+
const FileTemplate = `/* eslint-disable prettier/prettier */
|
|
34
|
+
// ************************************************************
|
|
35
|
+
// Note: this file is auto-generated, do not modify it directly
|
|
36
|
+
// ************************************************************
|
|
37
|
+
|
|
38
|
+
// It was generated by convertGlslIntoBlock() from
|
|
39
|
+
// an annotated .glsl file. Modify the .glsl file to make changes
|
|
40
|
+
// to the block. This file will get overwritten when the build
|
|
41
|
+
// is run or during a watch when the .glsl file is updated.
|
|
42
|
+
|
|
43
|
+
import type { Effect } from "@babylonjs/core/Materials/effect";
|
|
44
|
+
|
|
45
|
+
import {
|
|
46
|
+
ShaderBinding,
|
|
47
|
+
type RuntimeData,
|
|
48
|
+
ConnectionPointType,
|
|
49
|
+
type SmartFilter,
|
|
50
|
+
ShaderBlock,
|
|
51
|
+
type ShaderProgram,
|
|
52
|
+
} from "@babylonjs/smart-filters";${SHADER_PROGRAM}
|
|
53
|
+
/**
|
|
54
|
+
* The shader binding for the ${BLOCK_NAME}, used by the runtime
|
|
55
|
+
*/
|
|
56
|
+
class ${BLOCK_NAME}ShaderBinding extends ShaderBinding {
|
|
57
|
+
${SHADER_BINDING_PRIVATE_VARIABLES}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Creates a new shader binding instance for the block.
|
|
61
|
+
${SHADER_BINDING_CTOR_DOCSTRING_PARAMS}
|
|
62
|
+
*/
|
|
63
|
+
constructor(
|
|
64
|
+
${SHADER_BINDING_CTOR_PARAMS}
|
|
65
|
+
) {
|
|
66
|
+
super();
|
|
67
|
+
${SHADER_BINDING_CTOR}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Binds all the required data to the shader when rendering.
|
|
72
|
+
* @param effect - defines the effect to bind the data to
|
|
73
|
+
*/
|
|
74
|
+
public override bind(effect: Effect): void {
|
|
75
|
+
${SHADER_BINDING_BIND}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The implementation of the ${BLOCK_NAME}
|
|
81
|
+
*/
|
|
82
|
+
export class ${BLOCK_NAME} extends ShaderBlock {
|
|
83
|
+
/**
|
|
84
|
+
* The class name of the block.
|
|
85
|
+
*/
|
|
86
|
+
public static override ClassName = "${BLOCK_NAME}";
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The namespace of the block.
|
|
90
|
+
*/
|
|
91
|
+
public static override Namespace = "${NAMESPACE}";
|
|
92
|
+
|
|
93
|
+
${BLOCK_INPUT_PROPERTIES}
|
|
94
|
+
/**
|
|
95
|
+
* The shader program (vertex and fragment code) to use to render the block
|
|
96
|
+
*/
|
|
97
|
+
public static override ShaderCode = shaderProgram;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Instantiates a new ${BLOCK_NAME}.
|
|
101
|
+
* @param smartFilter - The smart filter this block belongs to
|
|
102
|
+
* @param name - The friendly name of the block
|
|
103
|
+
*/
|
|
104
|
+
constructor(smartFilter: SmartFilter, name: string) {
|
|
105
|
+
super(smartFilter, name);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Get the class instance that binds all the required data to the shader (effect) when rendering.
|
|
110
|
+
* @returns The class instance that binds the data to the effect
|
|
111
|
+
*/
|
|
112
|
+
public getShaderBinding(): ShaderBinding {
|
|
113
|
+
${BLOCK_GET_SHADER_BINDING_VARS}
|
|
114
|
+
|
|
115
|
+
return new ${BLOCK_NAME}ShaderBinding(${BLOCK_GET_SHADER_PARAM_LIST});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
`;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Converts a single shader to a .ts file which exports a Smart Filter block
|
|
123
|
+
* @param fragmentShaderPath - The path to the fragment file for the shader
|
|
124
|
+
* @param importPath - The path to import the ShaderProgram type from
|
|
125
|
+
*/
|
|
126
|
+
export function convertGlslIntoBlock(fragmentShaderPath: string, importPath: string): void {
|
|
127
|
+
const { shaderProgramCode, fragmentShaderInfo } = extractShaderProgramFromGlsl(
|
|
128
|
+
fragmentShaderPath,
|
|
129
|
+
importPath,
|
|
130
|
+
false,
|
|
131
|
+
false
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
// Validation
|
|
135
|
+
if (!fragmentShaderInfo.blockType) {
|
|
136
|
+
throw new Error("The glsl file must contain a header comment with a smartFilterBlockType value");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Generate shader binding private variables
|
|
140
|
+
const shaderBindingPrivateVariables = fragmentShaderInfo.uniforms.map((uniform) => {
|
|
141
|
+
return ShaderBindingPrivateVariablesTemplate.replace(CAMEL_CASE_UNIFORM, uniform.name).replace(
|
|
142
|
+
CONNECTION_POINT_TYPE,
|
|
143
|
+
getConnectionPointTypeString(uniform.type)
|
|
144
|
+
);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Generate the shader binding constructor docstring params
|
|
148
|
+
const shaderBindingCtorDocstringParams = fragmentShaderInfo.uniforms.map((uniform) => {
|
|
149
|
+
return ShaderBindingCtorDocstringParams.replace(new RegExp(CAMEL_CASE_UNIFORM, "g"), uniform.name);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Generate the shader binding constructor params
|
|
153
|
+
const shaderBindingCtorParams = fragmentShaderInfo.uniforms.map((uniform) => {
|
|
154
|
+
return ShaderBindingCtorParams.replace(CAMEL_CASE_UNIFORM, uniform.name).replace(
|
|
155
|
+
CONNECTION_POINT_TYPE,
|
|
156
|
+
getConnectionPointTypeString(uniform.type)
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Generate the shader binding constructor
|
|
161
|
+
const shaderBindingCtor = fragmentShaderInfo.uniforms.map((uniform) => {
|
|
162
|
+
return ShaderBindingCtor.replace(new RegExp(CAMEL_CASE_UNIFORM, "g"), uniform.name);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Generate the shader binding bind
|
|
166
|
+
const shaderBindingBind = fragmentShaderInfo.uniforms.map((uniform) => {
|
|
167
|
+
return ShaderBindingBind.replace(new RegExp(CAMEL_CASE_UNIFORM, "g"), uniform.name).replace(
|
|
168
|
+
EFFECT_SETTER,
|
|
169
|
+
getEffectSetter(uniform.type)
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Generate the block input properties
|
|
174
|
+
const blockInputProperties = fragmentShaderInfo.uniforms.map((uniform) => {
|
|
175
|
+
return BlockInputProperties.replace(new RegExp(CAMEL_CASE_UNIFORM, "g"), uniform.name).replace(
|
|
176
|
+
CONNECTION_POINT_TYPE,
|
|
177
|
+
getConnectionPointTypeString(uniform.type)
|
|
178
|
+
);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Generate the block get shader binding vars
|
|
182
|
+
const blockGetShaderBindingVars = fragmentShaderInfo.uniforms.map((uniform) => {
|
|
183
|
+
return BlockGetShaderBindingVars.replace(new RegExp(CAMEL_CASE_UNIFORM, "g"), uniform.name);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Generate the block get shader param list
|
|
187
|
+
const blockGetShaderParamList = fragmentShaderInfo.uniforms.map((uniform) => {
|
|
188
|
+
return uniform.name;
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Generate final contents
|
|
192
|
+
const finalContents = FileTemplate.replace(SHADER_PROGRAM, shaderProgramCode)
|
|
193
|
+
.replace(new RegExp(BLOCK_NAME, "g"), fragmentShaderInfo.blockType)
|
|
194
|
+
.replace(NAMESPACE, fragmentShaderInfo.namespace || "Other")
|
|
195
|
+
.replace(SHADER_BINDING_PRIVATE_VARIABLES, shaderBindingPrivateVariables.join("\n"))
|
|
196
|
+
.replace(SHADER_BINDING_CTOR_DOCSTRING_PARAMS, shaderBindingCtorDocstringParams.join("\n"))
|
|
197
|
+
.replace(SHADER_BINDING_CTOR_PARAMS, shaderBindingCtorParams.join(",\n"))
|
|
198
|
+
.replace(SHADER_BINDING_CTOR, shaderBindingCtor.join("\n"))
|
|
199
|
+
.replace(SHADER_BINDING_BIND, shaderBindingBind.join("\n"))
|
|
200
|
+
.replace(BLOCK_INPUT_PROPERTIES, blockInputProperties.join("\n"))
|
|
201
|
+
.replace(BLOCK_GET_SHADER_BINDING_VARS, blockGetShaderBindingVars.join("\n"))
|
|
202
|
+
.replace(BLOCK_GET_SHADER_PARAM_LIST, blockGetShaderParamList.join(","));
|
|
203
|
+
|
|
204
|
+
// Write the block class TS file
|
|
205
|
+
const outputFullPathAndFileName = fragmentShaderPath.replace(".glsl", ".ts");
|
|
206
|
+
fs.writeFileSync(outputFullPathAndFileName, finalContents);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Get the string representation of a connection point type
|
|
211
|
+
* @param type - The connection point type
|
|
212
|
+
* @returns - The string representation of the connection point type
|
|
213
|
+
*/
|
|
214
|
+
function getConnectionPointTypeString(type: ConnectionPointType): string {
|
|
215
|
+
switch (type) {
|
|
216
|
+
case ConnectionPointType.Float:
|
|
217
|
+
return "Float";
|
|
218
|
+
case ConnectionPointType.Texture:
|
|
219
|
+
return "Texture";
|
|
220
|
+
case ConnectionPointType.Color3:
|
|
221
|
+
return "Color3";
|
|
222
|
+
case ConnectionPointType.Color4:
|
|
223
|
+
return "Color4";
|
|
224
|
+
case ConnectionPointType.Vector2:
|
|
225
|
+
return "Vector2";
|
|
226
|
+
case ConnectionPointType.Boolean:
|
|
227
|
+
return "Boolean";
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Get the effect setter for a connection point type
|
|
233
|
+
* @param type - The connection point type
|
|
234
|
+
* @returns - The effect setter for the connection point type
|
|
235
|
+
*/
|
|
236
|
+
function getEffectSetter(type: ConnectionPointType): string {
|
|
237
|
+
switch (type) {
|
|
238
|
+
case ConnectionPointType.Float:
|
|
239
|
+
return "setFloat";
|
|
240
|
+
case ConnectionPointType.Texture:
|
|
241
|
+
return "setTexture";
|
|
242
|
+
case ConnectionPointType.Color3:
|
|
243
|
+
return "setColor3";
|
|
244
|
+
case ConnectionPointType.Color4:
|
|
245
|
+
return "setDirectColor4";
|
|
246
|
+
case ConnectionPointType.Vector2:
|
|
247
|
+
return "setVector2";
|
|
248
|
+
case ConnectionPointType.Boolean:
|
|
249
|
+
return "setBool";
|
|
250
|
+
}
|
|
251
|
+
}
|
package/src/utils/buildTools/{convertShaderForHardcodedBlock.ts → convertGlslIntoShaderProgram.ts}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
|
-
import
|
|
3
|
-
import { parseFragmentShader } from "./shaderConverter.js";
|
|
2
|
+
import { Logger } from "@babylonjs/core/Misc/logger.js";
|
|
3
|
+
import { parseFragmentShader, type FragmentShaderInfo } from "./shaderConverter.js";
|
|
4
4
|
|
|
5
5
|
const TYPE_IMPORT_PATH = "@TYPE_IMPORT_PATH@";
|
|
6
6
|
const VERTEX_SHADER = "@VERTEX_SHADER@";
|
|
@@ -13,6 +13,8 @@ const FUNCTIONS = "@FUNCTIONS@";
|
|
|
13
13
|
const FUNCTION_NAME = "@FUNCTION_NAME@";
|
|
14
14
|
const FUNCTION_CODE = "@FUNCTION_CODE@";
|
|
15
15
|
const UNIFORM_NAMES = "@UNIFORM_NAMES@";
|
|
16
|
+
const EXPORT = "@EXPORT_SHADER_PROGRAM@";
|
|
17
|
+
const IMPORTS = "@IMPORT@";
|
|
16
18
|
|
|
17
19
|
const ConstsTemplate = `
|
|
18
20
|
const: \`${CONSTS_VALUE}\`,`;
|
|
@@ -29,12 +31,13 @@ const CodeLinePrefix = " ";
|
|
|
29
31
|
const UniformLinePrefix = " ";
|
|
30
32
|
const ConstLinePrefix = " ";
|
|
31
33
|
|
|
32
|
-
const
|
|
34
|
+
const ImportTemplate = `import type { ShaderProgram } from "${TYPE_IMPORT_PATH}";`;
|
|
35
|
+
const ShaderTemplate = `${IMPORTS}
|
|
33
36
|
|
|
34
37
|
/**
|
|
35
38
|
* The shader program for the block.
|
|
36
39
|
*/
|
|
37
|
-
|
|
40
|
+
${EXPORT}const shaderProgram: ShaderProgram = {
|
|
38
41
|
vertex: ${VERTEX_SHADER},
|
|
39
42
|
fragment: {
|
|
40
43
|
uniform: \`${UNIFORMS}\`,${CONSTS_PROPERTY}
|
|
@@ -49,7 +52,7 @@ export const shaderProgram: ShaderProgram = {
|
|
|
49
52
|
* The uniform names for this shader, to be used in the shader binding so
|
|
50
53
|
* that the names are always in sync.
|
|
51
54
|
*/
|
|
52
|
-
|
|
55
|
+
${EXPORT}const uniforms = {
|
|
53
56
|
${UNIFORM_NAMES}
|
|
54
57
|
};
|
|
55
58
|
`;
|
|
@@ -57,29 +60,63 @@ ${UNIFORM_NAMES}
|
|
|
57
60
|
const UniformNameLinePrefix = " ";
|
|
58
61
|
|
|
59
62
|
/**
|
|
60
|
-
* Converts a single shader to a .ts file which can be imported by a hardcoded block
|
|
63
|
+
* Converts a single shader to a .ts file which exports a ShaderProgram which can be imported by a hardcoded block
|
|
61
64
|
* @param fragmentShaderPath - The path to the fragment file for the shader
|
|
62
65
|
* @param importPath - The path to import the ShaderProgram type from
|
|
63
66
|
*/
|
|
64
|
-
export function
|
|
65
|
-
|
|
67
|
+
export function convertGlslIntoShaderProgram(fragmentShaderPath: string, importPath: string): void {
|
|
68
|
+
const { shaderProgramCode } = extractShaderProgramFromGlsl(fragmentShaderPath, importPath, true, true);
|
|
69
|
+
const shaderFile = fragmentShaderPath.replace(".glsl", ".ts");
|
|
70
|
+
fs.writeFileSync(shaderFile, shaderProgramCode);
|
|
71
|
+
}
|
|
66
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Extracts the shader program from a glsl file(s) and returns it as a string which can be written to a .ts file
|
|
75
|
+
* @param fragmentShaderPath - The path to the fragment file for the shader
|
|
76
|
+
* @param importPath - The path to import the ShaderProgram type from
|
|
77
|
+
* @param exportObjects - Whether to export the shaderProgram and uniforms objects
|
|
78
|
+
* @param includeImports - Whether to include the imports in the output
|
|
79
|
+
* @returns The string to write to the .ts file
|
|
80
|
+
*/
|
|
81
|
+
export function extractShaderProgramFromGlsl(
|
|
82
|
+
fragmentShaderPath: string,
|
|
83
|
+
importPath: string,
|
|
84
|
+
exportObjects: boolean,
|
|
85
|
+
includeImports: boolean
|
|
86
|
+
): {
|
|
87
|
+
/**
|
|
88
|
+
* The shader program code
|
|
89
|
+
*/
|
|
90
|
+
shaderProgramCode: string;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The FragmentShaderInfo
|
|
94
|
+
*/
|
|
95
|
+
fragmentShaderInfo: FragmentShaderInfo;
|
|
96
|
+
} {
|
|
67
97
|
// See if there is a corresponding vertex shader
|
|
68
98
|
let vertexShader: string | undefined = undefined;
|
|
69
|
-
|
|
99
|
+
let extensionToFind: string;
|
|
100
|
+
if (fragmentShaderPath.endsWith(".block.glsl")) {
|
|
101
|
+
extensionToFind = ".block.glsl";
|
|
102
|
+
} else if (fragmentShaderPath.endsWith(".fragment.glsl")) {
|
|
103
|
+
extensionToFind = ".fragment.glsl";
|
|
104
|
+
} else {
|
|
105
|
+
throw new Error("The shader file must end with .fragment.glsl or .block.glsl");
|
|
106
|
+
}
|
|
107
|
+
const vertexShaderPath = fragmentShaderPath.replace(extensionToFind, ".vertex.glsl");
|
|
70
108
|
if (fs.existsSync(vertexShaderPath)) {
|
|
71
109
|
vertexShader = fs.readFileSync(vertexShaderPath, "utf8");
|
|
72
110
|
}
|
|
73
111
|
if (vertexShader) {
|
|
74
|
-
|
|
112
|
+
Logger.Log("Found vertex shader");
|
|
75
113
|
}
|
|
76
114
|
|
|
77
115
|
// Read the fragment shader
|
|
78
116
|
const fragmentShader = fs.readFileSync(fragmentShaderPath, "utf8");
|
|
79
117
|
const fragmentShaderInfo = parseFragmentShader(fragmentShader);
|
|
80
118
|
|
|
81
|
-
//
|
|
82
|
-
const shaderFile = fragmentShaderPath.replace(".fragment.glsl", ".shader.ts");
|
|
119
|
+
// Generate the shader program code
|
|
83
120
|
const functionsSection: string[] = [];
|
|
84
121
|
for (const shaderFunction of fragmentShaderInfo.shaderCode.functions) {
|
|
85
122
|
functionsSection.push(
|
|
@@ -89,11 +126,12 @@ export function convertShaderForHardcodedBlock(fragmentShaderPath: string, impor
|
|
|
89
126
|
)
|
|
90
127
|
);
|
|
91
128
|
}
|
|
129
|
+
const imports = includeImports ? ImportTemplate.replace(TYPE_IMPORT_PATH, importPath) : "";
|
|
92
130
|
const finalContents = ShaderTemplate.replace(VERTEX_SHADER, vertexShader ? `\`${vertexShader}\`` : "undefined")
|
|
93
|
-
.replace(
|
|
131
|
+
.replace(IMPORTS, imports)
|
|
94
132
|
.replace(UNIFORMS, "\n" + addLinePrefixes(fragmentShaderInfo.shaderCode.uniform || "", UniformLinePrefix))
|
|
95
133
|
.replace(MAIN_FUNCTION_NAME, fragmentShaderInfo.shaderCode.mainFunctionName)
|
|
96
|
-
.replace(MAIN_INPUT_NAME, fragmentShaderInfo.shaderCode.mainInputTexture ||
|
|
134
|
+
.replace(MAIN_INPUT_NAME, fragmentShaderInfo.shaderCode.mainInputTexture || "")
|
|
97
135
|
.replace(
|
|
98
136
|
CONSTS_PROPERTY,
|
|
99
137
|
fragmentShaderInfo.shaderCode.const
|
|
@@ -110,29 +148,13 @@ export function convertShaderForHardcodedBlock(fragmentShaderPath: string, impor
|
|
|
110
148
|
fragmentShaderInfo.uniforms.map((u) => `${u.name}: "${u.name}",`).join("\n"),
|
|
111
149
|
UniformNameLinePrefix
|
|
112
150
|
)
|
|
113
|
-
)
|
|
114
|
-
|
|
115
|
-
fs.writeFileSync(shaderFile, finalContents);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Converts .fragment.glsl and vertex.glsl file pairs into .shader.ts files which export a ShaderProgram object.
|
|
120
|
-
* @param shaderPath - The path to the .glsl files to convert.
|
|
121
|
-
* @param importPath - The path to import the ShaderProgram type from.
|
|
122
|
-
*/
|
|
123
|
-
export function convertShaders(shaderPath: string, importPath: string) {
|
|
124
|
-
// Get all files in the path
|
|
125
|
-
const allFiles = fs.readdirSync(shaderPath, { withFileTypes: true, recursive: true });
|
|
126
|
-
|
|
127
|
-
// Find all fragment shaders (excluding the template)
|
|
128
|
-
const fragmentShaderFiles = allFiles.filter(
|
|
129
|
-
(file) => file.isFile() && file.name.endsWith(".fragment.glsl") && !file.name.endsWith("template.fragment.glsl")
|
|
130
|
-
);
|
|
151
|
+
)
|
|
152
|
+
.replace(new RegExp(EXPORT, "g"), exportObjects ? "export " : "");
|
|
131
153
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
154
|
+
return {
|
|
155
|
+
shaderProgramCode: finalContents,
|
|
156
|
+
fragmentShaderInfo,
|
|
157
|
+
};
|
|
136
158
|
}
|
|
137
159
|
|
|
138
160
|
/**
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { Logger } from "@babylonjs/core/Misc/logger.js";
|
|
4
|
+
import { convertGlslIntoShaderProgram } from "./convertGlslIntoShaderProgram.js";
|
|
5
|
+
import { convertGlslIntoBlock } from "./convertGlslIntoBlock.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Converts all GLSL files in a path into blocks for use in the build system.
|
|
9
|
+
* @param shaderPath - The path to the .glsl files to convert.
|
|
10
|
+
* @param importPath - The path to import the ShaderProgram type from.
|
|
11
|
+
*/
|
|
12
|
+
export function convertShaders(shaderPath: string, importPath: string) {
|
|
13
|
+
// Get all files in the path
|
|
14
|
+
const allFiles = fs.readdirSync(shaderPath, { withFileTypes: true, recursive: true });
|
|
15
|
+
|
|
16
|
+
// Find all shaders (files with .fragment.glsl or .block.glsl extensions)
|
|
17
|
+
const shaderFiles = allFiles.filter(
|
|
18
|
+
(file) => file.isFile() && (file.name.endsWith(".fragment.glsl") || file.name.endsWith(".block.glsl"))
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
// Convert all shaders
|
|
22
|
+
for (const shaderFile of shaderFiles) {
|
|
23
|
+
const fullPathAndFileName = path.join(shaderFile.path, shaderFile.name);
|
|
24
|
+
convertShader(fullPathAndFileName, importPath);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Converts a single GLSL file into a block class or a ShaderProgram for use in the build system.
|
|
30
|
+
* @param fullPathAndFileName - The full path and file name of the .glsl file to convert.
|
|
31
|
+
* @param importPath - The path to import the ShaderProgram type from.
|
|
32
|
+
*/
|
|
33
|
+
export function convertShader(fullPathAndFileName: string, importPath: string): void {
|
|
34
|
+
Logger.Log(`\nProcessing shader: ${fullPathAndFileName}`);
|
|
35
|
+
|
|
36
|
+
if (fullPathAndFileName.endsWith(".fragment.glsl")) {
|
|
37
|
+
Logger.Log("Generating a .ts file that exports a ShaderProgram.");
|
|
38
|
+
convertGlslIntoShaderProgram(fullPathAndFileName, importPath);
|
|
39
|
+
} else if (fullPathAndFileName.endsWith(".block.glsl")) {
|
|
40
|
+
Logger.Log("Generating a .ts file that exports the block as a class.");
|
|
41
|
+
convertGlslIntoBlock(fullPathAndFileName, importPath);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Nullable } from "@babylonjs/core/types";
|
|
2
|
+
import { Logger } from "@babylonjs/core/Misc/logger.js";
|
|
2
3
|
import type { ShaderCode, ShaderFunction } from "./shaderCode.types";
|
|
4
|
+
import { ConnectionPointType } from "../../connection/connectionPointType.js";
|
|
3
5
|
|
|
4
6
|
const GetFunctionNamesRegEx = /\S*\w+\s+(\w+)\s*\(/g;
|
|
5
7
|
|
|
@@ -31,7 +33,7 @@ export type UniformMetadata = {
|
|
|
31
33
|
/**
|
|
32
34
|
* The type string of the uniform
|
|
33
35
|
*/
|
|
34
|
-
type:
|
|
36
|
+
type: ConnectionPointType;
|
|
35
37
|
|
|
36
38
|
/**
|
|
37
39
|
* Optional properties of the uniform
|
|
@@ -106,9 +108,34 @@ export function parseFragmentShader(fragmentShader: string): FragmentShaderInfo
|
|
|
106
108
|
throw new Error(`Uniforms must have a name: '${uniformLine}'`);
|
|
107
109
|
}
|
|
108
110
|
|
|
111
|
+
// Convert to ConnectionPointType
|
|
112
|
+
let type: ConnectionPointType;
|
|
113
|
+
switch (uniformTypeString) {
|
|
114
|
+
case "float":
|
|
115
|
+
type = ConnectionPointType.Float;
|
|
116
|
+
break;
|
|
117
|
+
case "sampler2D":
|
|
118
|
+
type = ConnectionPointType.Texture;
|
|
119
|
+
break;
|
|
120
|
+
case "vec3":
|
|
121
|
+
type = ConnectionPointType.Color3;
|
|
122
|
+
break;
|
|
123
|
+
case "vec4":
|
|
124
|
+
type = ConnectionPointType.Color4;
|
|
125
|
+
break;
|
|
126
|
+
case "bool":
|
|
127
|
+
type = ConnectionPointType.Boolean;
|
|
128
|
+
break;
|
|
129
|
+
case "vec2":
|
|
130
|
+
type = ConnectionPointType.Vector2;
|
|
131
|
+
break;
|
|
132
|
+
default:
|
|
133
|
+
throw new Error(`Unsupported uniform type: '${uniformTypeString}'`);
|
|
134
|
+
}
|
|
135
|
+
|
|
109
136
|
uniforms.push({
|
|
110
137
|
name: uniformName,
|
|
111
|
-
type
|
|
138
|
+
type,
|
|
112
139
|
properties: annotationJSON ? JSON.parse(annotationJSON.replace("//", "").trim()) : undefined,
|
|
113
140
|
});
|
|
114
141
|
|
|
@@ -123,13 +150,13 @@ export function parseFragmentShader(fragmentShader: string): FragmentShaderInfo
|
|
|
123
150
|
// Collect uniform, const, and function names which need to be decorated
|
|
124
151
|
// eslint-disable-next-line prettier/prettier
|
|
125
152
|
const uniformNames = uniforms.map((uniform) => uniform.name);
|
|
126
|
-
|
|
153
|
+
Logger.Log(`Uniforms found: ${JSON.stringify(uniforms)}`);
|
|
127
154
|
const consts = [...fragmentShader.matchAll(/\S*const\s+\w*\s+(\w*)\s*=.*;/g)].map((match) => match[1]);
|
|
128
|
-
|
|
155
|
+
Logger.Log(`Consts found: ${JSON.stringify(consts)}`);
|
|
129
156
|
const functionNames = [...fragmentShaderWithNoFunctionBodies.matchAll(GetFunctionNamesRegEx)].map(
|
|
130
157
|
(match) => match[1]
|
|
131
158
|
);
|
|
132
|
-
|
|
159
|
+
Logger.Log(`Functions found: ${JSON.stringify(functionNames)}`);
|
|
133
160
|
|
|
134
161
|
// Decorate the uniforms, consts, and functions
|
|
135
162
|
const symbolsToDecorate = [...uniformNames, ...consts, ...functionNames];
|
|
@@ -138,7 +165,7 @@ export function parseFragmentShader(fragmentShader: string): FragmentShaderInfo
|
|
|
138
165
|
const regex = new RegExp(`(?<=\\W+)${symbol}(?=\\W+)`, "gs");
|
|
139
166
|
fragmentShaderWithRenamedSymbols = fragmentShaderWithRenamedSymbols.replace(regex, `_${symbol}_`);
|
|
140
167
|
}
|
|
141
|
-
|
|
168
|
+
Logger.Log(`${symbolsToDecorate.length} symbol(s) renamed`);
|
|
142
169
|
|
|
143
170
|
// Extract all the uniforms
|
|
144
171
|
const finalUniforms = [...fragmentShaderWithRenamedSymbols.matchAll(/^\s*(uniform\s.*)/gm)].map(
|
|
@@ -308,7 +335,7 @@ function removeFunctionBodies(input: string): string {
|
|
|
308
335
|
}
|
|
309
336
|
|
|
310
337
|
if (depth !== 0) {
|
|
311
|
-
|
|
338
|
+
Logger.Error("Unbalanced curly braces in shader code");
|
|
312
339
|
}
|
|
313
340
|
|
|
314
341
|
return output;
|