@galacean/engine-shader-compiler 0.0.0-experimental-2.0-spine.0
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/LICENSE +21 -0
- package/README.md +43 -0
- package/bundler/cli.js +341 -0
- package/bundler/precompile.cjs.js +324 -0
- package/bundler/precompile.js +294 -0
- package/bundler/rollup.cjs.js +368 -0
- package/bundler/rollup.js +341 -0
- package/dist/browser.js +8938 -0
- package/dist/browser.js.map +1 -0
- package/dist/browser.min.js +2 -0
- package/dist/browser.min.js.map +1 -0
- package/dist/browser.verbose.js +9601 -0
- package/dist/browser.verbose.js.map +1 -0
- package/dist/browser.verbose.min.js +2 -0
- package/dist/browser.verbose.min.js.map +1 -0
- package/dist/main.js +8935 -0
- package/dist/main.js.map +1 -0
- package/dist/main.verbose.js +9598 -0
- package/dist/main.verbose.js.map +1 -0
- package/dist/module.js +8928 -0
- package/dist/module.js.map +1 -0
- package/dist/module.verbose.js +9591 -0
- package/dist/module.verbose.js.map +1 -0
- package/package.json +69 -0
- package/types/GSError.d.ts +16 -0
- package/types/ParserUtils.d.ts +39 -0
- package/types/Preprocessor.d.ts +30 -0
- package/types/ShaderCompiler.d.ts +21 -0
- package/types/ShaderCompilerUtils.d.ts +10 -0
- package/types/ShaderInstructionEncoder.d.ts +1 -0
- package/types/TempArray.d.ts +5 -0
- package/types/bundler/cli.d.ts +1 -0
- package/types/bundler/precompile.d.ts +25 -0
- package/types/bundler/rollup.d.ts +41 -0
- package/types/codeGen/CodeGenVisitor.d.ts +1 -0
- package/types/codeGen/GLES100.d.ts +12 -0
- package/types/codeGen/GLES300.d.ts +20 -0
- package/types/codeGen/GLESVisitor.d.ts +1 -0
- package/types/codeGen/VisitorContext.d.ts +2 -0
- package/types/codeGen/index.d.ts +3 -0
- package/types/codeGen/types.d.ts +12 -0
- package/types/common/BaseLexer.d.ts +2 -0
- package/types/common/BaseToken.d.ts +35 -0
- package/types/common/IBaseSymbol.d.ts +5 -0
- package/types/common/ShaderPosition.d.ts +8 -0
- package/types/common/ShaderRange.d.ts +8 -0
- package/types/common/SymbolTable.d.ts +9 -0
- package/types/common/SymbolTableStack.d.ts +13 -0
- package/types/common/enums/Keyword.d.ts +124 -0
- package/types/common/enums/ShaderStage.d.ts +5 -0
- package/types/common/index.d.ts +5 -0
- package/types/common/types.d.ts +101 -0
- package/types/index.d.ts +3 -0
- package/types/lalr/CFG.d.ts +5 -0
- package/types/lalr/LALR1.d.ts +27 -0
- package/types/lalr/Production.d.ts +9 -0
- package/types/lalr/State.d.ts +20 -0
- package/types/lalr/StateItem.d.ts +20 -0
- package/types/lalr/Utils.d.ts +22 -0
- package/types/lalr/index.d.ts +2 -0
- package/types/lalr/types.d.ts +14 -0
- package/types/lexer/Lexer.d.ts +143 -0
- package/types/lexer/index.d.ts +1 -0
- package/types/parser/AST.d.ts +502 -0
- package/types/parser/Grammar.d.ts +11 -0
- package/types/parser/GrammarSymbol.d.ts +128 -0
- package/types/parser/SemanticAnalyzer.d.ts +2 -0
- package/types/parser/ShaderInfo.d.ts +10 -0
- package/types/parser/ShaderTargetParser.d.ts +24 -0
- package/types/parser/builtin/functions.d.ts +34 -0
- package/types/parser/builtin/index.d.ts +2 -0
- package/types/parser/builtin/variables.d.ts +11 -0
- package/types/parser/index.d.ts +2 -0
- package/types/parser/symbolTable/FnSymbol.d.ts +6 -0
- package/types/parser/symbolTable/StructSymbol.d.ts +6 -0
- package/types/parser/symbolTable/SymbolDataType.d.ts +8 -0
- package/types/parser/symbolTable/SymbolInfo.d.ts +22 -0
- package/types/parser/symbolTable/VarSymbol.d.ts +8 -0
- package/types/parser/symbolTable/index.d.ts +6 -0
- package/types/parser/types.d.ts +24 -0
- package/types/sourceParser/ShaderSourceFactory.d.ts +8 -0
- package/types/sourceParser/ShaderSourceParser.d.ts +1 -0
- package/types/sourceParser/ShaderSourceSymbol.d.ts +10 -0
- package/types/sourceParser/SourceLexer.d.ts +19 -0
- package/types/sourceParser/index.d.ts +1 -0
- package/verbose/package.json +11 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 - present Ant Group
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
## Installation
|
|
2
|
+
|
|
3
|
+
```sh
|
|
4
|
+
npm install @galacean/engine-shader-compiler
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { ShaderCompiler } from "@galacean/engine-shader-compiler";
|
|
11
|
+
|
|
12
|
+
// Create shader compiler
|
|
13
|
+
const shaderCompiler = new ShaderCompiler();
|
|
14
|
+
|
|
15
|
+
// Create engine with shader compiler
|
|
16
|
+
const engine = await WebGLEngine.create({ canvas: "canvas", shaderCompiler });
|
|
17
|
+
|
|
18
|
+
......
|
|
19
|
+
|
|
20
|
+
// Create shader by galacean shader code directly
|
|
21
|
+
const shader = Shader.create(galaceanShaderCode);
|
|
22
|
+
|
|
23
|
+
.......
|
|
24
|
+
|
|
25
|
+
// Run engine
|
|
26
|
+
engine.run()
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
There are two versions of the shader compiler: `Release` and `Verbose`. The `Verbose` version offers more user-friendly diagnostic information for debugging shader compilation errors, while the Release version provides superior performance.
|
|
30
|
+
|
|
31
|
+
you can use `Verbose` version by import:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { ShaderCompiler } from "@galacean/engine-shader-compiler/verbose";
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## CFG Grammar conflict detection
|
|
38
|
+
|
|
39
|
+
The Galacean shader syntax is defined using Context-Free Grammar (CFG) and is documented within the `\*.y` file. When modifications to the shader syntax are required, it is recommended to make changes to the existing CFG syntax file, and employ [Bison](https://www.gnu.org/software/bison/manual/bison.html) to detect any potential grammar conflicts.
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
bison ./Parser.y -r all
|
|
43
|
+
```
|
package/bundler/cli.js
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from 'node:util';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { createRequire } from 'node:module';
|
|
6
|
+
import { pathToFileURL } from 'node:url';
|
|
7
|
+
|
|
8
|
+
/** Normalize to forward slashes (Windows uses `\`; downstream regex/keys assume `/`). */ function normalizePath(p) {
|
|
9
|
+
return p.split(path.sep).join("/");
|
|
10
|
+
}
|
|
11
|
+
/** Recursively find all files with a given extension. */ function findFiles(dir, ext) {
|
|
12
|
+
const results = [];
|
|
13
|
+
if (!fs.existsSync(dir)) return results;
|
|
14
|
+
for (const entry of fs.readdirSync(dir, {
|
|
15
|
+
withFileTypes: true
|
|
16
|
+
})){
|
|
17
|
+
const fullPath = path.join(dir, entry.name);
|
|
18
|
+
if (entry.isDirectory()) {
|
|
19
|
+
results.push(...findFiles(fullPath, ext));
|
|
20
|
+
} else if (entry.name.endsWith(ext)) {
|
|
21
|
+
results.push(normalizePath(fullPath));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return results;
|
|
25
|
+
}
|
|
26
|
+
/** `PBR.shaderc` → `PBRSource`, `2D/Sprite.shaderc` → `SpriteSource`. */ function shadercPathToVarName(relPath) {
|
|
27
|
+
const normalized = normalizePath(relPath).replace(/\.shaderc$/, "");
|
|
28
|
+
const base = normalized.split("/").pop() ?? normalized;
|
|
29
|
+
const cleaned = base.replace(/[^A-Za-z0-9]/g, "");
|
|
30
|
+
if (cleaned.length === 0) return "Source";
|
|
31
|
+
return `${cleaned[0].toUpperCase()}${cleaned.slice(1)}Source`;
|
|
32
|
+
}
|
|
33
|
+
/** `Common/Common.glsl` → `Common_Common` — TS identifier for source-index imports. */ function pathToIdentifier(rel, ext) {
|
|
34
|
+
let id = rel.replace(new RegExp(`\\${ext}$`), "").replace(/[^A-Za-z0-9_]/g, "_");
|
|
35
|
+
if (/^[0-9]/.test(id)) id = "_" + id;
|
|
36
|
+
return id;
|
|
37
|
+
}
|
|
38
|
+
/** Remove empty parent directories upward from `startDir` until `stopDir` is hit. */ function pruneEmptyDirs(startDir, stopDir) {
|
|
39
|
+
let dir = startDir;
|
|
40
|
+
while(dir !== stopDir && fs.existsSync(dir) && fs.readdirSync(dir).length === 0){
|
|
41
|
+
fs.rmdirSync(dir);
|
|
42
|
+
dir = path.dirname(dir);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// One-shot mode exits non-zero on failure so CI breaks; watch mode logs and keeps running.
|
|
46
|
+
async function precompile(options) {
|
|
47
|
+
const { failed } = await runFull(options);
|
|
48
|
+
if (options.watch) {
|
|
49
|
+
await startWatcher(options);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
console.log("[shader-compiler-bundler] Done.");
|
|
53
|
+
if (failed > 0) {
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function runFull(options) {
|
|
58
|
+
const inputDir = path.resolve(options.input);
|
|
59
|
+
const outputDir = path.resolve(options.output);
|
|
60
|
+
const platformTarget = options.platformTarget ?? 0;
|
|
61
|
+
if (!fs.existsSync(inputDir)) {
|
|
62
|
+
throw new Error(`Input directory does not exist: ${inputDir}`);
|
|
63
|
+
}
|
|
64
|
+
fs.mkdirSync(outputDir, {
|
|
65
|
+
recursive: true
|
|
66
|
+
});
|
|
67
|
+
// Emit source indexes before compile so collectIncludeMap can resolve the freshly-built sources.
|
|
68
|
+
if (options.emitSources) {
|
|
69
|
+
emitSources(inputDir);
|
|
70
|
+
}
|
|
71
|
+
const shaderCompiler = await loadShaderCompiler();
|
|
72
|
+
shaderCompiler._setIncludeMap(await collectIncludeMap(inputDir));
|
|
73
|
+
let failed = 0;
|
|
74
|
+
if (options.only) {
|
|
75
|
+
const target = path.resolve(options.only);
|
|
76
|
+
if (!compileSingle(shaderCompiler, target, inputDir, outputDir, platformTarget)) failed++;
|
|
77
|
+
} else {
|
|
78
|
+
const shaderFiles = findFiles(inputDir, ".shader");
|
|
79
|
+
console.log(`[shader-compiler-bundler] Precompiling ${shaderFiles.length} shader(s)...`);
|
|
80
|
+
for (const file of shaderFiles){
|
|
81
|
+
if (!compileSingle(shaderCompiler, file, inputDir, outputDir, platformTarget)) failed++;
|
|
82
|
+
}
|
|
83
|
+
if (options.clean) {
|
|
84
|
+
const removed = cleanOrphanedBundles(shaderFiles, inputDir, outputDir);
|
|
85
|
+
if (removed > 0) console.log(`[shader-compiler-bundler] Cleaned ${removed} orphaned .shaderc file(s).`);
|
|
86
|
+
}
|
|
87
|
+
if (failed > 0) console.warn(`[shader-compiler-bundler] ${failed} shader(s) failed to precompile.`);
|
|
88
|
+
}
|
|
89
|
+
if (options.emitIndex) {
|
|
90
|
+
emitIndex(outputDir);
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
failed
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
async function startWatcher(options) {
|
|
97
|
+
const inputDir = path.resolve(options.input);
|
|
98
|
+
const outputDir = path.resolve(options.output);
|
|
99
|
+
const platformTarget = options.platformTarget ?? 0;
|
|
100
|
+
const shaderCompiler = await loadShaderCompiler();
|
|
101
|
+
shaderCompiler._setIncludeMap(await collectIncludeMap(inputDir));
|
|
102
|
+
// .glsl change → full recompile (can't cheaply track include graphs).
|
|
103
|
+
// .shader change → single-file recompile.
|
|
104
|
+
const handleInputChange = async (filename)=>{
|
|
105
|
+
if (!filename) return;
|
|
106
|
+
const norm = normalizePath(filename);
|
|
107
|
+
const fullPath = path.join(inputDir, filename);
|
|
108
|
+
if (norm.endsWith(".glsl")) {
|
|
109
|
+
console.log(`[shader-compiler-bundler] Include changed (${norm}), full recompile...`);
|
|
110
|
+
shaderCompiler._setIncludeMap(await collectIncludeMap(inputDir));
|
|
111
|
+
runFull(options).catch((e)=>console.error(e));
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (!norm.endsWith(".shader")) return;
|
|
115
|
+
if (!fs.existsSync(fullPath)) {
|
|
116
|
+
removeBundleFor(fullPath, inputDir, outputDir);
|
|
117
|
+
} else {
|
|
118
|
+
compileSingle(shaderCompiler, fullPath, inputDir, outputDir, platformTarget);
|
|
119
|
+
}
|
|
120
|
+
if (options.emitSources) emitSources(inputDir);
|
|
121
|
+
if (options.emitIndex) emitIndex(outputDir);
|
|
122
|
+
};
|
|
123
|
+
console.log(`[shader-compiler-bundler] Watching ${inputDir} ...`);
|
|
124
|
+
fs.watch(inputDir, {
|
|
125
|
+
recursive: true
|
|
126
|
+
}, (_event, filename)=>{
|
|
127
|
+
handleInputChange(filename).catch((e)=>console.error(e));
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
async function loadShaderCompiler() {
|
|
131
|
+
// @ts-ignore — `../dist/main.js` is the compiled runtime entry; no .ts source.
|
|
132
|
+
// Bundler ships at `<pkg>/bundler/` and the runtime at `<pkg>/dist/`, so this
|
|
133
|
+
// resolves to the sibling `dist/` from `bundler/cli.js` at runtime.
|
|
134
|
+
const mod = await import('../dist/main.js');
|
|
135
|
+
const instance = new mod.ShaderCompiler();
|
|
136
|
+
if (typeof instance._precompile !== "function") {
|
|
137
|
+
throw new Error("ShaderCompiler._precompile is not available; rebuild @galacean/engine-shader-compiler first.");
|
|
138
|
+
}
|
|
139
|
+
return instance;
|
|
140
|
+
}
|
|
141
|
+
// Local .glsl come from inputDir; standard library comes from
|
|
142
|
+
// `@galacean/engine-shader/sources` with a sibling-dir fallback for engine self-build cold-start.
|
|
143
|
+
async function collectIncludeMap(inputDir) {
|
|
144
|
+
const map = {};
|
|
145
|
+
for (const file of findFiles(inputDir, ".glsl")){
|
|
146
|
+
const relPath = normalizePath(path.relative(inputDir, file));
|
|
147
|
+
map[relPath] = fs.readFileSync(file, "utf-8");
|
|
148
|
+
}
|
|
149
|
+
let usedRelease = false;
|
|
150
|
+
// Resolve from inputDir's node_modules so consumers without transitive linkage to shader-compiler can still find it.
|
|
151
|
+
try {
|
|
152
|
+
const requireFromInput = createRequire(path.join(inputDir, "package.json"));
|
|
153
|
+
const sourcesPath = requireFromInput.resolve("@galacean/engine-shader/sources");
|
|
154
|
+
const { shaderLibrary } = await import(pathToFileURL(sourcesPath).href);
|
|
155
|
+
for (const { source, path: chunkPath } of shaderLibrary){
|
|
156
|
+
map[chunkPath] = source;
|
|
157
|
+
}
|
|
158
|
+
usedRelease = true;
|
|
159
|
+
} catch {
|
|
160
|
+
// engine self-build cold-start: dist/sources.* not yet built; use sibling source.
|
|
161
|
+
}
|
|
162
|
+
if (!usedRelease) {
|
|
163
|
+
const siblingLibrary = path.join(path.dirname(inputDir), "ShaderLibrary");
|
|
164
|
+
if (fs.existsSync(siblingLibrary)) {
|
|
165
|
+
for (const file of findFiles(siblingLibrary, ".glsl")){
|
|
166
|
+
const rel = normalizePath(path.relative(siblingLibrary, file));
|
|
167
|
+
map[`ShaderLibrary/${rel}`] = fs.readFileSync(file, "utf-8");
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return map;
|
|
172
|
+
}
|
|
173
|
+
// Mirrors `ShaderPass._shaderRootPath` in engine; inlined to keep bundler engine-free.
|
|
174
|
+
const SHADER_ROOT_PATH = "shaders://root/";
|
|
175
|
+
function compileSingle(shaderCompiler, shaderPath, inputDir, outputDir, platformTarget) {
|
|
176
|
+
const source = fs.readFileSync(shaderPath, "utf-8");
|
|
177
|
+
const relativePath = normalizePath(path.relative(inputDir, shaderPath));
|
|
178
|
+
const bundleRelative = relativePath.replace(/\.shader$/, ".shaderc");
|
|
179
|
+
const bundlePath = path.join(outputDir, bundleRelative);
|
|
180
|
+
const basePathForIncludeKey = new URL(relativePath, SHADER_ROOT_PATH).href;
|
|
181
|
+
fs.mkdirSync(path.dirname(bundlePath), {
|
|
182
|
+
recursive: true
|
|
183
|
+
});
|
|
184
|
+
try {
|
|
185
|
+
const precompiled = shaderCompiler._precompile(source, platformTarget, basePathForIncludeKey);
|
|
186
|
+
fs.writeFileSync(bundlePath, JSON.stringify(precompiled));
|
|
187
|
+
console.log(` ${relativePath} -> ${bundleRelative}`);
|
|
188
|
+
return true;
|
|
189
|
+
} catch (e) {
|
|
190
|
+
console.error(` FAILED: ${relativePath}`);
|
|
191
|
+
console.error(e);
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function cleanOrphanedBundles(shaderFiles, inputDir, outputDir) {
|
|
196
|
+
const aliveSet = new Set(shaderFiles.map((f)=>normalizePath(path.relative(inputDir, f)).replace(/\.shader$/, "")));
|
|
197
|
+
const bundleFiles = findFiles(outputDir, ".shaderc");
|
|
198
|
+
let removed = 0;
|
|
199
|
+
for (const bundleFile of bundleFiles){
|
|
200
|
+
const rel = normalizePath(path.relative(outputDir, bundleFile)).replace(/\.shaderc$/, "");
|
|
201
|
+
if (!aliveSet.has(rel)) {
|
|
202
|
+
fs.unlinkSync(bundleFile);
|
|
203
|
+
console.log(` Removed orphaned: ${rel}.shaderc`);
|
|
204
|
+
removed++;
|
|
205
|
+
pruneEmptyDirs(path.dirname(bundleFile), outputDir);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return removed;
|
|
209
|
+
}
|
|
210
|
+
function emitIndex(outputDir) {
|
|
211
|
+
const bundleFiles = findFiles(outputDir, ".shaderc");
|
|
212
|
+
const entries = bundleFiles.map((file)=>{
|
|
213
|
+
const rel = normalizePath(path.relative(outputDir, file));
|
|
214
|
+
return {
|
|
215
|
+
varName: shadercPathToVarName(rel),
|
|
216
|
+
importPath: `./${rel}`
|
|
217
|
+
};
|
|
218
|
+
}).sort((a, b)=>a.varName.localeCompare(b.varName));
|
|
219
|
+
const imports = entries.map((e)=>`import ${e.varName} from "${e.importPath}";`).join("\n");
|
|
220
|
+
const exportBlock = `export {\n${entries.map((e)=>` ${e.varName}`).join(",\n")}\n};`;
|
|
221
|
+
// prettier-ignore the export block: consumer's prettier config is unknown.
|
|
222
|
+
const content = `// Auto-generated by shader-compiler-precompile --emit-index — do not edit.\n${imports}\n\n// prettier-ignore\n${exportBlock}\n`;
|
|
223
|
+
const indexPath = path.join(outputDir, "index.ts");
|
|
224
|
+
const existing = fs.existsSync(indexPath) ? fs.readFileSync(indexPath, "utf-8") : "";
|
|
225
|
+
if (content !== existing) {
|
|
226
|
+
fs.writeFileSync(indexPath, content);
|
|
227
|
+
console.log(" Updated index.ts");
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// Generate raw-source indexes:
|
|
231
|
+
// <inputDir>/index.ts — `.shader` array (defines IShaderSource interface)
|
|
232
|
+
// <sibling>/ShaderLibrary/index.ts — `.glsl` array (only if the directory exists)
|
|
233
|
+
function emitSources(inputDir) {
|
|
234
|
+
emitShaderSourceIndex(inputDir);
|
|
235
|
+
const libraryDir = path.join(path.dirname(inputDir), "ShaderLibrary");
|
|
236
|
+
if (fs.existsSync(libraryDir)) {
|
|
237
|
+
emitLibrarySourceIndex(libraryDir);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function emitShaderSourceIndex(rootDir) {
|
|
241
|
+
const srcDir = path.dirname(rootDir);
|
|
242
|
+
const files = findFiles(rootDir, ".shader").sort();
|
|
243
|
+
const importPaths = files.map((f)=>normalizePath(path.relative(rootDir, f)));
|
|
244
|
+
const paths = files.map((f)=>normalizePath(path.relative(srcDir, f)));
|
|
245
|
+
const ids = importPaths.map((p)=>pathToIdentifier(p, ".shader"));
|
|
246
|
+
const lines = [];
|
|
247
|
+
lines.push("// Auto-generated by shader-compiler-precompile --emit-sources — do not edit.");
|
|
248
|
+
lines.push("");
|
|
249
|
+
importPaths.forEach((rel, i)=>lines.push(`import ${ids[i]} from "./${rel}";`));
|
|
250
|
+
lines.push("");
|
|
251
|
+
lines.push("export interface IShaderSource {");
|
|
252
|
+
lines.push(" path: string;");
|
|
253
|
+
lines.push(" source: string;");
|
|
254
|
+
lines.push("}");
|
|
255
|
+
lines.push("");
|
|
256
|
+
lines.push("// prettier-ignore");
|
|
257
|
+
lines.push("export const shaders: IShaderSource[] = [");
|
|
258
|
+
paths.forEach((p, i)=>lines.push(` { source: ${ids[i]}, path: ${JSON.stringify(p)} },`));
|
|
259
|
+
lines.push("];");
|
|
260
|
+
lines.push("");
|
|
261
|
+
const out = path.join(rootDir, "index.ts");
|
|
262
|
+
fs.writeFileSync(out, lines.join("\n"), "utf-8");
|
|
263
|
+
console.log(` Emitted shaders index ${path.relative(process.cwd(), out)} (${files.length})`);
|
|
264
|
+
}
|
|
265
|
+
function emitLibrarySourceIndex(rootDir) {
|
|
266
|
+
const srcDir = path.dirname(rootDir);
|
|
267
|
+
const files = findFiles(rootDir, ".glsl").sort();
|
|
268
|
+
const importPaths = files.map((f)=>normalizePath(path.relative(rootDir, f)));
|
|
269
|
+
const paths = files.map((f)=>normalizePath(path.relative(srcDir, f)));
|
|
270
|
+
const ids = importPaths.map((p)=>pathToIdentifier(p, ".glsl"));
|
|
271
|
+
const lines = [];
|
|
272
|
+
lines.push("// Auto-generated by shader-compiler-precompile --emit-sources — do not edit.");
|
|
273
|
+
lines.push("");
|
|
274
|
+
lines.push(`import type { IShaderSource } from "../Shaders";`);
|
|
275
|
+
importPaths.forEach((rel, i)=>lines.push(`import ${ids[i]} from "./${rel}";`));
|
|
276
|
+
lines.push("");
|
|
277
|
+
lines.push("// prettier-ignore");
|
|
278
|
+
lines.push("export const shaderLibrary: IShaderSource[] = [");
|
|
279
|
+
paths.forEach((p, i)=>lines.push(` { source: ${ids[i]}, path: ${JSON.stringify(p)} },`));
|
|
280
|
+
lines.push("];");
|
|
281
|
+
lines.push("");
|
|
282
|
+
const out = path.join(rootDir, "index.ts");
|
|
283
|
+
fs.writeFileSync(out, lines.join("\n"), "utf-8");
|
|
284
|
+
console.log(` Emitted library index ${path.relative(process.cwd(), out)} (${files.length})`);
|
|
285
|
+
}
|
|
286
|
+
function removeBundleFor(shaderPath, inputDir, outputDir) {
|
|
287
|
+
const rel = normalizePath(path.relative(inputDir, shaderPath)).replace(/\.shader$/, ".shaderc");
|
|
288
|
+
const bundlePath = path.join(outputDir, rel);
|
|
289
|
+
if (fs.existsSync(bundlePath)) {
|
|
290
|
+
fs.unlinkSync(bundlePath);
|
|
291
|
+
console.log(` Removed: ${rel}`);
|
|
292
|
+
pruneEmptyDirs(path.dirname(bundlePath), outputDir);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Entry point for the `shader-compiler-precompile` bin.
|
|
298
|
+
*
|
|
299
|
+
* Usage:
|
|
300
|
+
* shader-compiler-precompile <input-dir> <output-dir>
|
|
301
|
+
* [--clean] [--watch] [--only <file>] [--emit-index] [--emit-sources]
|
|
302
|
+
*/ async function main() {
|
|
303
|
+
const { positionals, values } = parseArgs({
|
|
304
|
+
allowPositionals: true,
|
|
305
|
+
options: {
|
|
306
|
+
clean: {
|
|
307
|
+
type: "boolean"
|
|
308
|
+
},
|
|
309
|
+
watch: {
|
|
310
|
+
type: "boolean"
|
|
311
|
+
},
|
|
312
|
+
only: {
|
|
313
|
+
type: "string"
|
|
314
|
+
},
|
|
315
|
+
"emit-index": {
|
|
316
|
+
type: "boolean"
|
|
317
|
+
},
|
|
318
|
+
"emit-sources": {
|
|
319
|
+
type: "boolean"
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
const [input, output] = positionals;
|
|
324
|
+
if (!input || !output) {
|
|
325
|
+
console.error("Usage: shader-compiler-precompile <input-dir> <output-dir> [--clean] [--watch] [--only <file>] [--emit-index] [--emit-sources]");
|
|
326
|
+
process.exit(1);
|
|
327
|
+
}
|
|
328
|
+
await precompile({
|
|
329
|
+
input,
|
|
330
|
+
output,
|
|
331
|
+
clean: values.clean,
|
|
332
|
+
watch: values.watch,
|
|
333
|
+
only: values.only,
|
|
334
|
+
emitIndex: values["emit-index"],
|
|
335
|
+
emitSources: values["emit-sources"]
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
main().catch((err)=>{
|
|
339
|
+
console.error(err);
|
|
340
|
+
process.exit(1);
|
|
341
|
+
});
|