@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
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var fs = require('node:fs');
|
|
6
|
+
var path = require('node:path');
|
|
7
|
+
var node_module = require('node:module');
|
|
8
|
+
var node_url = require('node:url');
|
|
9
|
+
|
|
10
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
11
|
+
|
|
12
|
+
function _interopNamespace(e) {
|
|
13
|
+
if (e && e.__esModule) return e;
|
|
14
|
+
var n = Object.create(null);
|
|
15
|
+
if (e) {
|
|
16
|
+
Object.keys(e).forEach(function (k) {
|
|
17
|
+
if (k !== 'default') {
|
|
18
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
19
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () { return e[k]; }
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
n["default"] = e;
|
|
27
|
+
return Object.freeze(n);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
31
|
+
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
32
|
+
|
|
33
|
+
/** Normalize to forward slashes (Windows uses `\`; downstream regex/keys assume `/`). */ function normalizePath(p) {
|
|
34
|
+
return p.split(path__default["default"].sep).join("/");
|
|
35
|
+
}
|
|
36
|
+
/** Recursively find all files with a given extension. */ function findFiles(dir, ext) {
|
|
37
|
+
const results = [];
|
|
38
|
+
if (!fs__default["default"].existsSync(dir)) return results;
|
|
39
|
+
for (const entry of fs__default["default"].readdirSync(dir, {
|
|
40
|
+
withFileTypes: true
|
|
41
|
+
})){
|
|
42
|
+
const fullPath = path__default["default"].join(dir, entry.name);
|
|
43
|
+
if (entry.isDirectory()) {
|
|
44
|
+
results.push(...findFiles(fullPath, ext));
|
|
45
|
+
} else if (entry.name.endsWith(ext)) {
|
|
46
|
+
results.push(normalizePath(fullPath));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return results;
|
|
50
|
+
}
|
|
51
|
+
/** `PBR.shaderc` → `PBRSource`, `2D/Sprite.shaderc` → `SpriteSource`. */ function shadercPathToVarName(relPath) {
|
|
52
|
+
const normalized = normalizePath(relPath).replace(/\.shaderc$/, "");
|
|
53
|
+
const base = normalized.split("/").pop() ?? normalized;
|
|
54
|
+
const cleaned = base.replace(/[^A-Za-z0-9]/g, "");
|
|
55
|
+
if (cleaned.length === 0) return "Source";
|
|
56
|
+
return `${cleaned[0].toUpperCase()}${cleaned.slice(1)}Source`;
|
|
57
|
+
}
|
|
58
|
+
/** `Common/Common.glsl` → `Common_Common` — TS identifier for source-index imports. */ function pathToIdentifier(rel, ext) {
|
|
59
|
+
let id = rel.replace(new RegExp(`\\${ext}$`), "").replace(/[^A-Za-z0-9_]/g, "_");
|
|
60
|
+
if (/^[0-9]/.test(id)) id = "_" + id;
|
|
61
|
+
return id;
|
|
62
|
+
}
|
|
63
|
+
/** Remove empty parent directories upward from `startDir` until `stopDir` is hit. */ function pruneEmptyDirs(startDir, stopDir) {
|
|
64
|
+
let dir = startDir;
|
|
65
|
+
while(dir !== stopDir && fs__default["default"].existsSync(dir) && fs__default["default"].readdirSync(dir).length === 0){
|
|
66
|
+
fs__default["default"].rmdirSync(dir);
|
|
67
|
+
dir = path__default["default"].dirname(dir);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function runFull(options) {
|
|
71
|
+
const inputDir = path__default["default"].resolve(options.input);
|
|
72
|
+
const outputDir = path__default["default"].resolve(options.output);
|
|
73
|
+
const platformTarget = options.platformTarget ?? 0;
|
|
74
|
+
if (!fs__default["default"].existsSync(inputDir)) {
|
|
75
|
+
throw new Error(`Input directory does not exist: ${inputDir}`);
|
|
76
|
+
}
|
|
77
|
+
fs__default["default"].mkdirSync(outputDir, {
|
|
78
|
+
recursive: true
|
|
79
|
+
});
|
|
80
|
+
// Emit source indexes before compile so collectIncludeMap can resolve the freshly-built sources.
|
|
81
|
+
if (options.emitSources) {
|
|
82
|
+
emitSources(inputDir);
|
|
83
|
+
}
|
|
84
|
+
const shaderCompiler = await loadShaderCompiler();
|
|
85
|
+
shaderCompiler._setIncludeMap(await collectIncludeMap(inputDir));
|
|
86
|
+
let failed = 0;
|
|
87
|
+
if (options.only) {
|
|
88
|
+
const target = path__default["default"].resolve(options.only);
|
|
89
|
+
if (!compileSingle(shaderCompiler, target, inputDir, outputDir, platformTarget)) failed++;
|
|
90
|
+
} else {
|
|
91
|
+
const shaderFiles = findFiles(inputDir, ".shader");
|
|
92
|
+
console.log(`[shader-compiler-bundler] Precompiling ${shaderFiles.length} shader(s)...`);
|
|
93
|
+
for (const file of shaderFiles){
|
|
94
|
+
if (!compileSingle(shaderCompiler, file, inputDir, outputDir, platformTarget)) failed++;
|
|
95
|
+
}
|
|
96
|
+
if (options.clean) {
|
|
97
|
+
const removed = cleanOrphanedBundles(shaderFiles, inputDir, outputDir);
|
|
98
|
+
if (removed > 0) console.log(`[shader-compiler-bundler] Cleaned ${removed} orphaned .shaderc file(s).`);
|
|
99
|
+
}
|
|
100
|
+
if (failed > 0) console.warn(`[shader-compiler-bundler] ${failed} shader(s) failed to precompile.`);
|
|
101
|
+
}
|
|
102
|
+
if (options.emitIndex) {
|
|
103
|
+
emitIndex(outputDir);
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
failed
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
async function startWatcher(options) {
|
|
110
|
+
const inputDir = path__default["default"].resolve(options.input);
|
|
111
|
+
const outputDir = path__default["default"].resolve(options.output);
|
|
112
|
+
const platformTarget = options.platformTarget ?? 0;
|
|
113
|
+
const shaderCompiler = await loadShaderCompiler();
|
|
114
|
+
shaderCompiler._setIncludeMap(await collectIncludeMap(inputDir));
|
|
115
|
+
// .glsl change → full recompile (can't cheaply track include graphs).
|
|
116
|
+
// .shader change → single-file recompile.
|
|
117
|
+
const handleInputChange = async (filename)=>{
|
|
118
|
+
if (!filename) return;
|
|
119
|
+
const norm = normalizePath(filename);
|
|
120
|
+
const fullPath = path__default["default"].join(inputDir, filename);
|
|
121
|
+
if (norm.endsWith(".glsl")) {
|
|
122
|
+
console.log(`[shader-compiler-bundler] Include changed (${norm}), full recompile...`);
|
|
123
|
+
shaderCompiler._setIncludeMap(await collectIncludeMap(inputDir));
|
|
124
|
+
runFull(options).catch((e)=>console.error(e));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (!norm.endsWith(".shader")) return;
|
|
128
|
+
if (!fs__default["default"].existsSync(fullPath)) {
|
|
129
|
+
removeBundleFor(fullPath, inputDir, outputDir);
|
|
130
|
+
} else {
|
|
131
|
+
compileSingle(shaderCompiler, fullPath, inputDir, outputDir, platformTarget);
|
|
132
|
+
}
|
|
133
|
+
if (options.emitSources) emitSources(inputDir);
|
|
134
|
+
if (options.emitIndex) emitIndex(outputDir);
|
|
135
|
+
};
|
|
136
|
+
console.log(`[shader-compiler-bundler] Watching ${inputDir} ...`);
|
|
137
|
+
fs__default["default"].watch(inputDir, {
|
|
138
|
+
recursive: true
|
|
139
|
+
}, (_event, filename)=>{
|
|
140
|
+
handleInputChange(filename).catch((e)=>console.error(e));
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
async function loadShaderCompiler() {
|
|
144
|
+
// @ts-ignore — `../dist/main.js` is the compiled runtime entry; no .ts source.
|
|
145
|
+
// Bundler ships at `<pkg>/bundler/` and the runtime at `<pkg>/dist/`, so this
|
|
146
|
+
// resolves to the sibling `dist/` from `bundler/cli.js` at runtime.
|
|
147
|
+
const mod = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('../dist/main.js')); });
|
|
148
|
+
const instance = new mod.ShaderCompiler();
|
|
149
|
+
if (typeof instance._precompile !== "function") {
|
|
150
|
+
throw new Error("ShaderCompiler._precompile is not available; rebuild @galacean/engine-shader-compiler first.");
|
|
151
|
+
}
|
|
152
|
+
return instance;
|
|
153
|
+
}
|
|
154
|
+
// Local .glsl come from inputDir; standard library comes from
|
|
155
|
+
// `@galacean/engine-shader/sources` with a sibling-dir fallback for engine self-build cold-start.
|
|
156
|
+
async function collectIncludeMap(inputDir) {
|
|
157
|
+
const map = {};
|
|
158
|
+
for (const file of findFiles(inputDir, ".glsl")){
|
|
159
|
+
const relPath = normalizePath(path__default["default"].relative(inputDir, file));
|
|
160
|
+
map[relPath] = fs__default["default"].readFileSync(file, "utf-8");
|
|
161
|
+
}
|
|
162
|
+
let usedRelease = false;
|
|
163
|
+
// Resolve from inputDir's node_modules so consumers without transitive linkage to shader-compiler can still find it.
|
|
164
|
+
try {
|
|
165
|
+
const requireFromInput = node_module.createRequire(path__default["default"].join(inputDir, "package.json"));
|
|
166
|
+
const sourcesPath = requireFromInput.resolve("@galacean/engine-shader/sources");
|
|
167
|
+
const { shaderLibrary } = await (function (t) { return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(t)); }); })(node_url.pathToFileURL(sourcesPath).href);
|
|
168
|
+
for (const { source, path: chunkPath } of shaderLibrary){
|
|
169
|
+
map[chunkPath] = source;
|
|
170
|
+
}
|
|
171
|
+
usedRelease = true;
|
|
172
|
+
} catch {
|
|
173
|
+
// engine self-build cold-start: dist/sources.* not yet built; use sibling source.
|
|
174
|
+
}
|
|
175
|
+
if (!usedRelease) {
|
|
176
|
+
const siblingLibrary = path__default["default"].join(path__default["default"].dirname(inputDir), "ShaderLibrary");
|
|
177
|
+
if (fs__default["default"].existsSync(siblingLibrary)) {
|
|
178
|
+
for (const file of findFiles(siblingLibrary, ".glsl")){
|
|
179
|
+
const rel = normalizePath(path__default["default"].relative(siblingLibrary, file));
|
|
180
|
+
map[`ShaderLibrary/${rel}`] = fs__default["default"].readFileSync(file, "utf-8");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return map;
|
|
185
|
+
}
|
|
186
|
+
// Mirrors `ShaderPass._shaderRootPath` in engine; inlined to keep bundler engine-free.
|
|
187
|
+
const SHADER_ROOT_PATH = "shaders://root/";
|
|
188
|
+
function compileSingle(shaderCompiler, shaderPath, inputDir, outputDir, platformTarget) {
|
|
189
|
+
const source = fs__default["default"].readFileSync(shaderPath, "utf-8");
|
|
190
|
+
const relativePath = normalizePath(path__default["default"].relative(inputDir, shaderPath));
|
|
191
|
+
const bundleRelative = relativePath.replace(/\.shader$/, ".shaderc");
|
|
192
|
+
const bundlePath = path__default["default"].join(outputDir, bundleRelative);
|
|
193
|
+
const basePathForIncludeKey = new URL(relativePath, SHADER_ROOT_PATH).href;
|
|
194
|
+
fs__default["default"].mkdirSync(path__default["default"].dirname(bundlePath), {
|
|
195
|
+
recursive: true
|
|
196
|
+
});
|
|
197
|
+
try {
|
|
198
|
+
const precompiled = shaderCompiler._precompile(source, platformTarget, basePathForIncludeKey);
|
|
199
|
+
fs__default["default"].writeFileSync(bundlePath, JSON.stringify(precompiled));
|
|
200
|
+
console.log(` ${relativePath} -> ${bundleRelative}`);
|
|
201
|
+
return true;
|
|
202
|
+
} catch (e) {
|
|
203
|
+
console.error(` FAILED: ${relativePath}`);
|
|
204
|
+
console.error(e);
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function cleanOrphanedBundles(shaderFiles, inputDir, outputDir) {
|
|
209
|
+
const aliveSet = new Set(shaderFiles.map((f)=>normalizePath(path__default["default"].relative(inputDir, f)).replace(/\.shader$/, "")));
|
|
210
|
+
const bundleFiles = findFiles(outputDir, ".shaderc");
|
|
211
|
+
let removed = 0;
|
|
212
|
+
for (const bundleFile of bundleFiles){
|
|
213
|
+
const rel = normalizePath(path__default["default"].relative(outputDir, bundleFile)).replace(/\.shaderc$/, "");
|
|
214
|
+
if (!aliveSet.has(rel)) {
|
|
215
|
+
fs__default["default"].unlinkSync(bundleFile);
|
|
216
|
+
console.log(` Removed orphaned: ${rel}.shaderc`);
|
|
217
|
+
removed++;
|
|
218
|
+
pruneEmptyDirs(path__default["default"].dirname(bundleFile), outputDir);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return removed;
|
|
222
|
+
}
|
|
223
|
+
function emitIndex(outputDir) {
|
|
224
|
+
const bundleFiles = findFiles(outputDir, ".shaderc");
|
|
225
|
+
const entries = bundleFiles.map((file)=>{
|
|
226
|
+
const rel = normalizePath(path__default["default"].relative(outputDir, file));
|
|
227
|
+
return {
|
|
228
|
+
varName: shadercPathToVarName(rel),
|
|
229
|
+
importPath: `./${rel}`
|
|
230
|
+
};
|
|
231
|
+
}).sort((a, b)=>a.varName.localeCompare(b.varName));
|
|
232
|
+
const imports = entries.map((e)=>`import ${e.varName} from "${e.importPath}";`).join("\n");
|
|
233
|
+
const exportBlock = `export {\n${entries.map((e)=>` ${e.varName}`).join(",\n")}\n};`;
|
|
234
|
+
// prettier-ignore the export block: consumer's prettier config is unknown.
|
|
235
|
+
const content = `// Auto-generated by shader-compiler-precompile --emit-index — do not edit.\n${imports}\n\n// prettier-ignore\n${exportBlock}\n`;
|
|
236
|
+
const indexPath = path__default["default"].join(outputDir, "index.ts");
|
|
237
|
+
const existing = fs__default["default"].existsSync(indexPath) ? fs__default["default"].readFileSync(indexPath, "utf-8") : "";
|
|
238
|
+
if (content !== existing) {
|
|
239
|
+
fs__default["default"].writeFileSync(indexPath, content);
|
|
240
|
+
console.log(" Updated index.ts");
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
// Generate raw-source indexes:
|
|
244
|
+
// <inputDir>/index.ts — `.shader` array (defines IShaderSource interface)
|
|
245
|
+
// <sibling>/ShaderLibrary/index.ts — `.glsl` array (only if the directory exists)
|
|
246
|
+
function emitSources(inputDir) {
|
|
247
|
+
emitShaderSourceIndex(inputDir);
|
|
248
|
+
const libraryDir = path__default["default"].join(path__default["default"].dirname(inputDir), "ShaderLibrary");
|
|
249
|
+
if (fs__default["default"].existsSync(libraryDir)) {
|
|
250
|
+
emitLibrarySourceIndex(libraryDir);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function emitShaderSourceIndex(rootDir) {
|
|
254
|
+
const srcDir = path__default["default"].dirname(rootDir);
|
|
255
|
+
const files = findFiles(rootDir, ".shader").sort();
|
|
256
|
+
const importPaths = files.map((f)=>normalizePath(path__default["default"].relative(rootDir, f)));
|
|
257
|
+
const paths = files.map((f)=>normalizePath(path__default["default"].relative(srcDir, f)));
|
|
258
|
+
const ids = importPaths.map((p)=>pathToIdentifier(p, ".shader"));
|
|
259
|
+
const lines = [];
|
|
260
|
+
lines.push("// Auto-generated by shader-compiler-precompile --emit-sources — do not edit.");
|
|
261
|
+
lines.push("");
|
|
262
|
+
importPaths.forEach((rel, i)=>lines.push(`import ${ids[i]} from "./${rel}";`));
|
|
263
|
+
lines.push("");
|
|
264
|
+
lines.push("export interface IShaderSource {");
|
|
265
|
+
lines.push(" path: string;");
|
|
266
|
+
lines.push(" source: string;");
|
|
267
|
+
lines.push("}");
|
|
268
|
+
lines.push("");
|
|
269
|
+
lines.push("// prettier-ignore");
|
|
270
|
+
lines.push("export const shaders: IShaderSource[] = [");
|
|
271
|
+
paths.forEach((p, i)=>lines.push(` { source: ${ids[i]}, path: ${JSON.stringify(p)} },`));
|
|
272
|
+
lines.push("];");
|
|
273
|
+
lines.push("");
|
|
274
|
+
const out = path__default["default"].join(rootDir, "index.ts");
|
|
275
|
+
fs__default["default"].writeFileSync(out, lines.join("\n"), "utf-8");
|
|
276
|
+
console.log(` Emitted shaders index ${path__default["default"].relative(process.cwd(), out)} (${files.length})`);
|
|
277
|
+
}
|
|
278
|
+
function emitLibrarySourceIndex(rootDir) {
|
|
279
|
+
const srcDir = path__default["default"].dirname(rootDir);
|
|
280
|
+
const files = findFiles(rootDir, ".glsl").sort();
|
|
281
|
+
const importPaths = files.map((f)=>normalizePath(path__default["default"].relative(rootDir, f)));
|
|
282
|
+
const paths = files.map((f)=>normalizePath(path__default["default"].relative(srcDir, f)));
|
|
283
|
+
const ids = importPaths.map((p)=>pathToIdentifier(p, ".glsl"));
|
|
284
|
+
const lines = [];
|
|
285
|
+
lines.push("// Auto-generated by shader-compiler-precompile --emit-sources — do not edit.");
|
|
286
|
+
lines.push("");
|
|
287
|
+
lines.push(`import type { IShaderSource } from "../Shaders";`);
|
|
288
|
+
importPaths.forEach((rel, i)=>lines.push(`import ${ids[i]} from "./${rel}";`));
|
|
289
|
+
lines.push("");
|
|
290
|
+
lines.push("// prettier-ignore");
|
|
291
|
+
lines.push("export const shaderLibrary: IShaderSource[] = [");
|
|
292
|
+
paths.forEach((p, i)=>lines.push(` { source: ${ids[i]}, path: ${JSON.stringify(p)} },`));
|
|
293
|
+
lines.push("];");
|
|
294
|
+
lines.push("");
|
|
295
|
+
const out = path__default["default"].join(rootDir, "index.ts");
|
|
296
|
+
fs__default["default"].writeFileSync(out, lines.join("\n"), "utf-8");
|
|
297
|
+
console.log(` Emitted library index ${path__default["default"].relative(process.cwd(), out)} (${files.length})`);
|
|
298
|
+
}
|
|
299
|
+
function removeBundleFor(shaderPath, inputDir, outputDir) {
|
|
300
|
+
const rel = normalizePath(path__default["default"].relative(inputDir, shaderPath)).replace(/\.shader$/, ".shaderc");
|
|
301
|
+
const bundlePath = path__default["default"].join(outputDir, rel);
|
|
302
|
+
if (fs__default["default"].existsSync(bundlePath)) {
|
|
303
|
+
fs__default["default"].unlinkSync(bundlePath);
|
|
304
|
+
console.log(` Removed: ${rel}`);
|
|
305
|
+
pruneEmptyDirs(path__default["default"].dirname(bundlePath), outputDir);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Pure transformer: take a file's id + source and emit JS module source.
|
|
311
|
+
*
|
|
312
|
+
* - `.shaderc` → exports the embedded JSON literal as the default export.
|
|
313
|
+
* - `.shader`/`.glsl` → exports the raw source as a string literal.
|
|
314
|
+
*/ function transformAsModule(code, id) {
|
|
315
|
+
if (id.endsWith(".shaderc")) {
|
|
316
|
+
return {
|
|
317
|
+
code: `export default ${code};`,
|
|
318
|
+
map: {
|
|
319
|
+
mappings: ""
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
code: `export default ${JSON.stringify(code)};`,
|
|
325
|
+
map: {
|
|
326
|
+
mappings: ""
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Rollup plugin that transforms shader assets into JS modules.
|
|
332
|
+
*
|
|
333
|
+
* - Always: transforms `.glsl` / `.shader` / `.shaderc` files.
|
|
334
|
+
* - When `precompile` option is set: runs a full precompile in buildStart and,
|
|
335
|
+
* in watch mode, starts a background watcher that mirrors `.shader` source
|
|
336
|
+
* changes into `.shaderc` outputs and refreshes the aggregated index.
|
|
337
|
+
*/ function shaderCompiler(options = {}) {
|
|
338
|
+
const { filter, precompile } = options;
|
|
339
|
+
const precompileOptions = precompile && {
|
|
340
|
+
clean: true,
|
|
341
|
+
emitIndex: true,
|
|
342
|
+
...precompile
|
|
343
|
+
};
|
|
344
|
+
let initialDone = false;
|
|
345
|
+
let watcherStarted = false;
|
|
346
|
+
return {
|
|
347
|
+
name: "shader-compiler",
|
|
348
|
+
async buildStart () {
|
|
349
|
+
if (!precompileOptions || initialDone) return;
|
|
350
|
+
initialDone = true;
|
|
351
|
+
await runFull(precompileOptions);
|
|
352
|
+
if (this.meta.watchMode && !watcherStarted) {
|
|
353
|
+
watcherStarted = true;
|
|
354
|
+
startWatcher(precompileOptions).catch((e)=>this.warn(`[shader-compiler] watcher failed: ${e.message}`));
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
transform (code, id) {
|
|
358
|
+
const normalized = normalizePath(id);
|
|
359
|
+
if (!normalized.match(/\.(glsl|shader|shaderc)$/)) return null;
|
|
360
|
+
if (filter && !filter(normalized)) return null;
|
|
361
|
+
return {
|
|
362
|
+
code: transformAsModule(code, normalized).code
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
exports.shaderCompiler = shaderCompiler;
|