-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRun.hx
More file actions
332 lines (273 loc) · 8.55 KB
/
Run.hx
File metadata and controls
332 lines (273 loc) · 8.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
package;
import haxe.io.Path;
import sys.FileSystem;
import sys.io.File;
using StringTools;
/**
* CLI entry point for `haxelib run shade`
*
* Transpiles Haxe shader files to GLSL or Unity shader formats.
*/
var commandRunDir:String = "";
var shadeRoot:String = "";
function main() {
final args = Sys.args();
// Last argument is the directory where the command was invoked
commandRunDir = args.pop();
// Determine shade library root (where this Run.hx is located)
shadeRoot = Path.directory(FileSystem.absolutePath(Sys.programPath()));
if (args.length == 0 || args[0] == "help" || args[0] == "--help" || args[0] == "-h") {
printHelp();
return;
}
// Ensure reflaxe is set up as a dev library
setupReflaxe();
transpileShaders(args);
}
function transpileShaders(args:Array<String>) {
// Parse arguments
var hxFiles:Array<String> = [];
var outputPath:Null<String> = null;
var target:Null<String> = null;
var extraHxml:Null<String> = null;
var i = 0;
while (i < args.length) {
final arg = args[i];
if (arg == "--in" && i + 1 < args.length) {
var file = args[i + 1];
if (!Path.isAbsolute(file)) {
file = Path.join([commandRunDir, file]);
}
hxFiles.push(file);
i += 2;
} else if (arg == "--out" && i + 1 < args.length) {
outputPath = args[i + 1];
if (!Path.isAbsolute(outputPath)) {
outputPath = Path.join([commandRunDir, outputPath]);
}
i += 2;
} else if (arg == "--target" && i + 1 < args.length) {
target = args[i + 1];
i += 2;
} else if (arg == "--hxml" && i + 1 < args.length) {
extraHxml = args[i + 1];
i += 2;
} else {
i++;
}
}
// Validate arguments
if (hxFiles.length == 0) {
printError("Error: At least one --in argument is required");
printHelp();
Sys.exit(1);
return;
}
if (target == null) {
printError("Error: --target argument is required (glsl or unity)");
printHelp();
Sys.exit(1);
return;
}
if (target != "glsl" && target != "unity" && target != "custom") {
printError('Error: Unknown target "$target". Valid targets: glsl, unity, custom');
Sys.exit(1);
return;
}
if (outputPath == null) {
outputPath = commandRunDir;
}
// Verify input files exist
for (hxFile in hxFiles) {
if (!FileSystem.exists(hxFile)) {
printError('Error: Input file not found: $hxFile');
Sys.exit(1);
return;
}
}
// Step 1: Create a temporary directory
final tempDir = createTempDir("shade-compile");
// Step 2: Copy shader files with correct package structure
for (hxFile in hxFiles) {
final pkg = extractPackageFromHaxeFile(hxFile);
final typeName = getTypeName(hxFile);
var destPath:String;
if (pkg != null) {
final pkgPath = pkg.replace(".", "/");
destPath = Path.join([tempDir, pkgPath, typeName + ".hx"]);
} else {
destPath = Path.join([tempDir, typeName + ".hx"]);
}
copyFile(hxFile, destPath);
}
// Step 3: Generate import.hx
final importContent = "import shade.*;\nimport shade.Functions.*;\n";
File.saveContent(Path.join([tempDir, "import.hx"]), importContent);
// Step 4: Generate Main.hx
final mainContent = new StringBuf();
for (hxFile in hxFiles) {
final fullType = getFullTypePath(hxFile);
mainContent.add('import $fullType;\n');
}
mainContent.add("\nfunction main() {\n}\n");
File.saveContent(Path.join([tempDir, "Main.hx"]), mainContent.toString());
// Step 5: Generate build.hxml
final shadePath = Path.join([shadeRoot, "src"]);
final shadeOutputDir = Path.join([tempDir, "shade-out"]);
final hxmlContent = new StringBuf();
// Local class path (the temp dir itself)
hxmlContent.add("-cp .\n");
// Reflaxe library (via haxelib, set up by setupReflaxe)
hxmlContent.add("-lib reflaxe\n");
// Shade library
hxmlContent.add('-cp $shadePath\n');
hxmlContent.add("-D shade\n");
// Required Haxe compiler settings for reflaxe/shade
hxmlContent.add("--dce no\n");
hxmlContent.add("-D analyzer-no-module\n");
hxmlContent.add("-D retain-untyped-meta\n");
// Shade compiler initialization
hxmlContent.add("--macro shade.compiler.CompilerInit.Start()\n");
// Add target-specific defines
switch (target) {
case "glsl":
hxmlContent.add("-D shade_glsl\n");
case "unity":
hxmlContent.add("-D shade_unity\n");
case "custom":
hxmlContent.add("-D shade_custom\n");
}
// Set output directory
hxmlContent.add('-D shade_output=$shadeOutputDir\n');
// Add user-provided hxml if any
if (extraHxml != null) {
hxmlContent.add('$extraHxml\n');
}
hxmlContent.add("-main Main\n");
hxmlContent.add("--no-output\n");
File.saveContent(Path.join([tempDir, "build.hxml"]), hxmlContent.toString());
// Step 6: Run Haxe compiler
Sys.println("Compiling shaders...");
final oldCwd = Sys.getCwd();
Sys.setCwd(tempDir);
final result = Sys.command("haxe", ["build.hxml"]);
Sys.setCwd(oldCwd);
if (result != 0) {
printError("Shader compilation failed");
deleteRecursive(tempDir);
Sys.exit(1);
return;
}
// Step 7: Copy generated shaders to output directory
if (!FileSystem.exists(outputPath)) {
createDirectoryRecursive(outputPath);
}
var copiedFiles = 0;
if (FileSystem.exists(shadeOutputDir)) {
for (file in FileSystem.readDirectory(shadeOutputDir)) {
if (file == "_GeneratedFiles.json")
continue;
final srcPath = Path.join([shadeOutputDir, file]);
final dstPath = Path.join([outputPath, file]);
File.copy(srcPath, dstPath);
copiedFiles++;
}
}
// Step 8: Clean up temporary directory
deleteRecursive(tempDir);
printSuccess('Successfully generated $copiedFiles shader file(s) in: $outputPath');
}
function printHelp() {
Sys.println("
Shade - Cross-platform shader transpiler
Usage:
haxelib run shade --in <shader.hx> --target <glsl|unity> [--out <dir>] [--hxml <extra>]
Arguments:
--in <path> Input Haxe shader file (can be specified multiple times)
--target <type> Target backend: glsl, unity, or custom
--out <dir> Output directory (default: current directory)
--hxml <content> Additional hxml compiler options
Examples:
haxelib run shade --in src/Blur.hx --target glsl --out shaders/
haxelib run shade --in src/Blur.hx --in src/Bloom.hx --target unity --out output/
haxelib run shade --in src/Custom.hx --target glsl --hxml \"-D my_define\"
");
}
function printError(msg:String) {
Sys.println('\033[1;31m$msg\033[0m');
}
function printSuccess(msg:String) {
Sys.println('\033[1;32m$msg\033[0m');
}
function extractPackageFromHaxeFile(filePath:String):Null<String> {
final content = File.getContent(filePath);
final packageRegex = ~/^package\s+([a-zA-Z_][a-zA-Z0-9_\.]*)\s*;/m;
if (packageRegex.match(content)) {
return packageRegex.matched(1);
}
return null;
}
function getTypeName(filePath:String):String {
return Path.withoutExtension(Path.withoutDirectory(filePath));
}
function getFullTypePath(filePath:String):String {
final pkg = extractPackageFromHaxeFile(filePath);
final typeName = getTypeName(filePath);
return pkg != null ? '$pkg.$typeName' : typeName;
}
function createTempDir(prefix:String):String {
final tempBase = switch (Sys.systemName()) {
case "Windows": Sys.getEnv("TEMP");
case _: "/tmp";
}
final timestamp = Date.now().getTime();
final random = Std.random(100000);
final tempDir = Path.join([tempBase, '${prefix}_${timestamp}_$random']);
createDirectoryRecursive(tempDir);
return tempDir;
}
function createDirectoryRecursive(path:String) {
if (FileSystem.exists(path))
return;
final parent = Path.directory(path);
if (parent != "" && parent != path && !FileSystem.exists(parent)) {
createDirectoryRecursive(parent);
}
FileSystem.createDirectory(path);
}
function deleteRecursive(path:String) {
if (!FileSystem.exists(path))
return;
if (FileSystem.isDirectory(path)) {
for (entry in FileSystem.readDirectory(path)) {
deleteRecursive(Path.join([path, entry]));
}
FileSystem.deleteDirectory(path);
} else {
FileSystem.deleteFile(path);
}
}
function copyFile(src:String, dest:String) {
final destDir = Path.directory(dest);
if (!FileSystem.exists(destDir)) {
createDirectoryRecursive(destDir);
}
File.copy(src, dest);
}
function setupReflaxe() {
// Set up reflaxe as a dev library pointing to our bundled git submodule
final reflaxePath = Path.join([shadeRoot, "git", "reflaxe"]);
if (!FileSystem.exists(reflaxePath)) {
printError('Error: reflaxe submodule not found at $reflaxePath');
printError("Please run: git submodule update --init");
Sys.exit(1);
return;
}
// Run haxelib dev reflaxe to point to our bundled version
// This is silent if already set up correctly
final result = Sys.command("haxelib", ["dev", "reflaxe", reflaxePath]);
if (result != 0) {
printError("Error: Failed to set up reflaxe library");
Sys.exit(1);
}
}