three-usd-robot 0.9.0 → 0.11.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.
@@ -1,4 +1,4 @@
1
- import { Quat, multiply, makeTranslation, makeRotationFromQuat, identity4, invert, makeEuler, DEG2RAD, makeRotationZ, makeRotationY, makeRotationX, fromUsdMatrix, makeScale, AssetPath, RAD2DEG, UsdMatrix } from './chunk-IYKPVUZ2.js';
1
+ import { Quat, multiply, makeTranslation, makeRotationFromQuat, identity4, invert, makeEuler, DEG2RAD, makeRotationZ, makeRotationY, makeRotationX, fromUsdMatrix, makeScale, RAD2DEG, AssetPath, UsdMatrix } from './chunk-LDO5FKQS.js';
2
2
  import { unzipSync } from 'fflate';
3
3
 
4
4
  // src/schemas/usdGeom.ts
@@ -21,8 +21,22 @@ var SOLID_GPRIM_TYPES = /* @__PURE__ */ new Set([
21
21
  function isSolidGprim(prim) {
22
22
  return SOLID_GPRIM_TYPES.has(prim.GetTypeName());
23
23
  }
24
+ function isPoints(prim) {
25
+ return prim.GetTypeName() === "Points";
26
+ }
27
+ function isBasisCurves(prim) {
28
+ return prim.GetTypeName() === "BasisCurves";
29
+ }
30
+ var UNSUPPORTED_GPRIM_TYPES = /* @__PURE__ */ new Set([
31
+ "NurbsCurves",
32
+ "HermiteCurves",
33
+ "NurbsPatch"
34
+ ]);
35
+ function isUnsupportedGprim(prim) {
36
+ return UNSUPPORTED_GPRIM_TYPES.has(prim.GetTypeName());
37
+ }
24
38
  function isRenderableGprim(prim) {
25
- return isMesh(prim) || isSolidGprim(prim);
39
+ return isMesh(prim) || isSolidGprim(prim) || isPoints(prim) || isBasisCurves(prim);
26
40
  }
27
41
  function getPurpose(prim) {
28
42
  const v = prim.GetAttribute("purpose").Get();
@@ -268,105 +282,634 @@ function asMatrix(v, where) {
268
282
  throw new Error(`${where}: expected a matrix`);
269
283
  }
270
284
 
285
+ // src/usd/AssetResolver.ts
286
+ var DefaultAssetResolver = class {
287
+ resolve(assetPath, baseUrl) {
288
+ try {
289
+ return new URL(assetPath, baseUrl || void 0).href;
290
+ } catch {
291
+ return joinPosix(baseUrl, assetPath);
292
+ }
293
+ }
294
+ async fetchText(url) {
295
+ const res = await fetch(url);
296
+ if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
297
+ return res.text();
298
+ }
299
+ async fetchBytes(url) {
300
+ const res = await fetch(url);
301
+ if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
302
+ return new Uint8Array(await res.arrayBuffer());
303
+ }
304
+ };
305
+ function createMemoryResolver(files) {
306
+ const decoder = new TextDecoder();
307
+ const encoder = new TextEncoder();
308
+ return {
309
+ resolve(assetPath, baseUrl) {
310
+ return joinPosix(baseUrl, assetPath);
311
+ },
312
+ fetchText(url) {
313
+ const v = files[url];
314
+ if (v === void 0) return Promise.reject(new Error(`asset not found: ${url}`));
315
+ return Promise.resolve(typeof v === "string" ? v : decoder.decode(v));
316
+ },
317
+ fetchBytes(url) {
318
+ const v = files[url];
319
+ if (v === void 0) return Promise.reject(new Error(`asset not found: ${url}`));
320
+ return Promise.resolve(typeof v === "string" ? encoder.encode(v) : v);
321
+ }
322
+ };
323
+ }
324
+ function joinPosix(baseUrl, rel) {
325
+ if (rel.startsWith("/")) return normalizePosix(rel);
326
+ const dir = baseUrl.slice(0, baseUrl.lastIndexOf("/") + 1);
327
+ return normalizePosix(dir + rel);
328
+ }
329
+ function normalizePosix(path) {
330
+ const isAbsolute = path.startsWith("/");
331
+ const out = [];
332
+ for (const part of path.split("/")) {
333
+ if (part === "" || part === ".") continue;
334
+ if (part === "..") out.pop();
335
+ else out.push(part);
336
+ }
337
+ return (isAbsolute ? "/" : "") + out.join("/");
338
+ }
339
+
340
+ // src/usd/mdl/parseMdl.ts
341
+ function isMdlTexture(value) {
342
+ return typeof value === "object" && value !== null && !Array.isArray(value) && "assetPath" in value;
343
+ }
344
+ function parseMdl(text) {
345
+ const src = stripNoise(text);
346
+ const materials = /* @__PURE__ */ new Map();
347
+ const declRe = /\bexport\s+material\s+([A-Za-z_]\w*)\s*\(/g;
348
+ let match = declRe.exec(src);
349
+ while (match) {
350
+ const open = match.index + match[0].length - 1;
351
+ const close = matchParen(src, open);
352
+ if (close === -1) break;
353
+ const decl = {
354
+ name: match[1],
355
+ defaults: parseParamDefaults(src.slice(open + 1, close - 1)),
356
+ args: /* @__PURE__ */ new Map()
357
+ };
358
+ let next = close;
359
+ let i = close;
360
+ while (i < src.length && /\s/.test(src[i])) i++;
361
+ if (src[i] === "=") {
362
+ const end = statementEnd(src, i + 1);
363
+ const body = parseWrapperBody(src.slice(i + 1, end));
364
+ if (body.base) decl.base = body.base;
365
+ decl.args = body.args;
366
+ next = end;
367
+ }
368
+ materials.set(decl.name, decl);
369
+ declRe.lastIndex = next;
370
+ match = declRe.exec(src);
371
+ }
372
+ return { materials };
373
+ }
374
+ var NUMBER_RE = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?[fFdD]?$/;
375
+ var CALL_RE = /^(?:::)?([A-Za-z_]\w*(?:::[A-Za-z_]\w*)*)\s*\(/;
376
+ var VECTOR_RE = /^(?:color|(?:float|double|int)([234]))$/;
377
+ var IDENTIFIER_RE = /^[A-Za-z_]\w*$/;
378
+ function parseMdlLiteral(src) {
379
+ const s = src.trim();
380
+ if (s === "true") return true;
381
+ if (s === "false") return false;
382
+ if (NUMBER_RE.test(s)) return Number.parseFloat(s.replace(/[fFdD]$/, ""));
383
+ if (s.startsWith('"')) {
384
+ if (skipString(s, 0) !== s.length) return void 0;
385
+ return s.slice(1, -1).replace(/\\(.)/g, "$1");
386
+ }
387
+ const call = CALL_RE.exec(s);
388
+ if (!call) return void 0;
389
+ const open = call[0].length - 1;
390
+ if (matchParen(s, open) !== s.length) return void 0;
391
+ const name = call[1].split("::").pop();
392
+ const args = splitTopLevel(s.slice(open + 1, s.length - 1), ",").map((a) => a.trim()).filter((a) => a.length > 0);
393
+ if (name === "texture_2d") {
394
+ const path = args[0] === void 0 ? void 0 : parseMdlLiteral(args[0]);
395
+ if (typeof path !== "string" || path.length === 0) return void 0;
396
+ const texture = { assetPath: path };
397
+ const gamma = args.slice(1).join(",");
398
+ if (gamma.includes("gamma_srgb")) texture.sourceColorSpace = "sRGB";
399
+ else if (gamma.includes("gamma_linear")) texture.sourceColorSpace = "raw";
400
+ return texture;
401
+ }
402
+ const vector = VECTOR_RE.exec(name);
403
+ if (vector) {
404
+ const width = vector[1] ? Number(vector[1]) : 3;
405
+ const values = args.map((a) => parseMdlLiteral(a));
406
+ if (values.length === 0 || !values.every((v) => typeof v === "number")) return void 0;
407
+ if (values.length === 1) return new Array(width).fill(values[0]);
408
+ return values.length === width ? values : void 0;
409
+ }
410
+ return void 0;
411
+ }
412
+ function parseParamDefaults(src) {
413
+ const defaults = /* @__PURE__ */ new Map();
414
+ const body = src.trim();
415
+ if (body === "" || body === "*") return defaults;
416
+ for (const param of splitTopLevel(src, ",")) {
417
+ const assign = topLevelAssign(param);
418
+ if (assign === -1) continue;
419
+ const name = param.slice(0, assign).trim().split(/\s+/).pop();
420
+ if (!name || !IDENTIFIER_RE.test(name)) continue;
421
+ const value = parseMdlLiteral(param.slice(assign + 1));
422
+ if (value !== void 0) defaults.set(name, value);
423
+ }
424
+ return defaults;
425
+ }
426
+ function parseWrapperBody(src) {
427
+ const args = /* @__PURE__ */ new Map();
428
+ const body = src.trim();
429
+ const call = CALL_RE.exec(body);
430
+ if (!call) return { args };
431
+ const open = call[0].length - 1;
432
+ if (matchParen(body, open) !== body.length) return { args };
433
+ const base = call[1].split("::").pop();
434
+ if (base === "material") return { args };
435
+ for (const arg of splitTopLevel(body.slice(open + 1, body.length - 1), ",")) {
436
+ const colon = topLevelColon(arg);
437
+ if (colon === -1) continue;
438
+ const name = arg.slice(0, colon).trim();
439
+ if (!IDENTIFIER_RE.test(name)) continue;
440
+ const value = parseMdlLiteral(arg.slice(colon + 1));
441
+ if (value !== void 0) args.set(name, value);
442
+ }
443
+ return { base, args };
444
+ }
445
+ function stripNoise(src) {
446
+ let out = "";
447
+ let i = 0;
448
+ while (i < src.length) {
449
+ const c = src[i];
450
+ if (c === '"') {
451
+ const end = skipString(src, i);
452
+ out += src.slice(i, end);
453
+ i = end;
454
+ } else if (c === "/" && src[i + 1] === "/") {
455
+ while (i < src.length && src[i] !== "\n") i++;
456
+ } else if (c === "/" && src[i + 1] === "*") {
457
+ const end = src.indexOf("*/", i + 2);
458
+ i = end === -1 ? src.length : end + 2;
459
+ out += " ";
460
+ } else if (c === "[" && src[i + 1] === "[") {
461
+ i = skipAnnotation(src, i);
462
+ out += " ";
463
+ } else {
464
+ out += c;
465
+ i++;
466
+ }
467
+ }
468
+ return out;
469
+ }
470
+ function skipString(src, i) {
471
+ let j = i + 1;
472
+ while (j < src.length) {
473
+ if (src[j] === "\\") j += 2;
474
+ else if (src[j] === '"') return j + 1;
475
+ else j++;
476
+ }
477
+ return j;
478
+ }
479
+ function skipAnnotation(src, i) {
480
+ let depth = 0;
481
+ let j = i;
482
+ while (j < src.length) {
483
+ if (src[j] === '"') {
484
+ j = skipString(src, j);
485
+ } else if (src[j] === "[" && src[j + 1] === "[") {
486
+ depth++;
487
+ j += 2;
488
+ } else if (src[j] === "]" && src[j + 1] === "]") {
489
+ depth--;
490
+ j += 2;
491
+ if (depth === 0) return j;
492
+ } else {
493
+ j++;
494
+ }
495
+ }
496
+ return j;
497
+ }
498
+ function matchParen(src, open) {
499
+ let depth = 0;
500
+ let i = open;
501
+ while (i < src.length) {
502
+ const c = src[i];
503
+ if (c === '"') {
504
+ i = skipString(src, i);
505
+ continue;
506
+ }
507
+ if (c === "(") depth++;
508
+ else if (c === ")") {
509
+ depth--;
510
+ if (depth === 0) return i + 1;
511
+ }
512
+ i++;
513
+ }
514
+ return -1;
515
+ }
516
+ function isOpener(c) {
517
+ return c === "(" || c === "[" || c === "{";
518
+ }
519
+ function isCloser(c) {
520
+ return c === ")" || c === "]" || c === "}";
521
+ }
522
+ function splitTopLevel(src, separator) {
523
+ const parts = [];
524
+ let depth = 0;
525
+ let start = 0;
526
+ let i = 0;
527
+ while (i < src.length) {
528
+ const c = src[i];
529
+ if (c === '"') {
530
+ i = skipString(src, i);
531
+ continue;
532
+ }
533
+ if (isOpener(c)) depth++;
534
+ else if (isCloser(c)) depth--;
535
+ else if (c === separator && depth === 0) {
536
+ parts.push(src.slice(start, i));
537
+ start = i + 1;
538
+ }
539
+ i++;
540
+ }
541
+ parts.push(src.slice(start));
542
+ return parts;
543
+ }
544
+ function statementEnd(src, from) {
545
+ let depth = 0;
546
+ let i = from;
547
+ while (i < src.length) {
548
+ const c = src[i];
549
+ if (c === '"') {
550
+ i = skipString(src, i);
551
+ continue;
552
+ }
553
+ if (isOpener(c)) depth++;
554
+ else if (isCloser(c)) depth--;
555
+ else if (c === ";" && depth === 0) return i;
556
+ i++;
557
+ }
558
+ return src.length;
559
+ }
560
+ function topLevelAssign(src) {
561
+ let depth = 0;
562
+ let i = 0;
563
+ while (i < src.length) {
564
+ const c = src[i];
565
+ if (c === '"') {
566
+ i = skipString(src, i);
567
+ continue;
568
+ }
569
+ if (isOpener(c)) depth++;
570
+ else if (isCloser(c)) depth--;
571
+ else if (c === "=" && depth === 0 && src[i + 1] !== "=" && !"<>!=".includes(src[i - 1] ?? "")) {
572
+ return i;
573
+ }
574
+ i++;
575
+ }
576
+ return -1;
577
+ }
578
+ function topLevelColon(src) {
579
+ let depth = 0;
580
+ let i = 0;
581
+ while (i < src.length) {
582
+ const c = src[i];
583
+ if (c === '"') {
584
+ i = skipString(src, i);
585
+ continue;
586
+ }
587
+ if (isOpener(c)) depth++;
588
+ else if (isCloser(c)) depth--;
589
+ else if (c === ":" && depth === 0) {
590
+ if (src[i + 1] === ":") {
591
+ i += 2;
592
+ continue;
593
+ }
594
+ return i;
595
+ }
596
+ i++;
597
+ }
598
+ return -1;
599
+ }
600
+
271
601
  // src/three/MaterialBinding.ts
272
602
  var DIFFUSE_INPUTS = [
273
- "inputs:diffuseColor",
603
+ "diffuseColor",
274
604
  // UsdPreviewSurface
275
- "inputs:diffuse_color_constant",
605
+ "diffuse_color_constant",
276
606
  // OmniPBR
277
- "inputs:diffuse_tint",
278
- "inputs:base_color",
279
- "inputs:baseColor"
607
+ "diffuse_tint",
608
+ "base_color",
609
+ "baseColor"
280
610
  ];
281
- var OPACITY_INPUTS = ["inputs:opacity", "inputs:opacity_constant"];
282
- var OPACITY_THRESHOLD_INPUTS = ["inputs:opacityThreshold", "inputs:opacity_threshold"];
283
- var METALLIC_INPUTS = ["inputs:metallic", "inputs:metallic_constant"];
284
- var ROUGHNESS_INPUTS = ["inputs:roughness", "inputs:reflection_roughness_constant"];
285
- var EMISSIVE_INPUTS = ["inputs:emissiveColor", "inputs:emissive_color"];
611
+ var OPACITY_INPUTS = ["opacity", "opacity_constant"];
612
+ var OPACITY_THRESHOLD_INPUTS = ["opacityThreshold", "opacity_threshold"];
613
+ var METALLIC_INPUTS = ["metallic", "metallic_constant"];
614
+ var ROUGHNESS_INPUTS = ["roughness", "reflection_roughness_constant"];
615
+ var EMISSIVE_INPUTS = ["emissiveColor", "emissive_color"];
286
616
  var SURFACE_OUTPUTS = ["outputs:surface", "outputs:mdl:surface"];
287
617
  var TEXTURE_LOOKUPS = {
288
618
  color: {
289
- surface: ["inputs:diffuseColor"],
290
- direct: ["inputs:diffuse_texture", "inputs:diffuse_color_texture"]
619
+ surface: ["diffuseColor"],
620
+ direct: ["diffuse_texture", "diffuse_color_texture", "glass_color_texture"]
291
621
  },
292
622
  opacity: {
293
- surface: ["inputs:opacity"],
294
- direct: ["inputs:opacity_texture", "inputs:opacity_color_texture"]
623
+ surface: ["opacity"],
624
+ direct: ["opacity_texture", "opacity_color_texture"]
295
625
  },
296
626
  normal: {
297
- surface: ["inputs:normal"],
298
- direct: ["inputs:normalmap_texture", "inputs:normal_texture"]
627
+ surface: ["normal"],
628
+ direct: ["normalmap_texture", "normal_texture", "normal_map_texture"]
299
629
  },
300
630
  roughness: {
301
- surface: ["inputs:roughness"],
302
- direct: ["inputs:reflectionroughness_texture", "inputs:roughness_texture"]
631
+ surface: ["roughness"],
632
+ direct: ["reflectionroughness_texture", "roughness_texture"]
303
633
  },
304
634
  metalness: {
305
- surface: ["inputs:metallic"],
306
- direct: ["inputs:metallic_texture"]
635
+ surface: ["metallic"],
636
+ direct: ["metallic_texture"]
307
637
  },
308
638
  occlusion: {
309
- surface: ["inputs:occlusion"],
310
- direct: ["inputs:ao_texture", "inputs:occlusion_texture"]
639
+ surface: ["occlusion"],
640
+ direct: ["ao_texture", "occlusion_texture"]
311
641
  },
312
642
  emissive: {
313
- surface: ["inputs:emissiveColor"],
314
- direct: ["inputs:emissive_color_texture", "inputs:emissive_mask_texture"]
643
+ surface: ["emissiveColor"],
644
+ direct: ["emissive_color_texture", "emissive_mask_texture"]
315
645
  }
316
646
  };
317
- function resolveBoundMaterial(stage, prim) {
647
+ function resolveBoundMaterial(stage, prim, options = {}) {
318
648
  const materialPath = findBinding(prim);
319
649
  if (!materialPath) return void 0;
320
650
  const material = stage.GetPrimAtPath(materialPath);
321
651
  if (!material) return void 0;
322
652
  const shader = findSurfaceShader(material);
323
653
  if (!shader) return void 0;
654
+ const mdlSource = readMdlShaderSource(shader, options.mdl);
655
+ if (mdlSource && !mdlSource.family) {
656
+ options.onWarn?.(
657
+ `${material.GetPath()}: unknown MDL material "${mdlSource.id}" (${mdlSource.assetPath}); applying the best-effort OmniPBR mapping`
658
+ );
659
+ }
660
+ const sv = { shader };
661
+ if (mdlSource?.values) sv.mdl = mdlSource.values;
662
+ if (mdlSource) sv.mdlAssetPath = mdlSource.assetPath;
324
663
  const result = { name: material.GetName() };
325
- const color = firstColor(shader, DIFFUSE_INPUTS);
664
+ const color = firstColor(sv, DIFFUSE_INPUTS);
326
665
  if (color) result.color = color;
327
- const opacity = firstNumber(shader, OPACITY_INPUTS);
666
+ const opacity = firstNumber(sv, OPACITY_INPUTS);
328
667
  if (opacity !== void 0) result.opacity = opacity;
329
- const opacityThreshold = firstNumber(shader, OPACITY_THRESHOLD_INPUTS);
668
+ const opacityThreshold = firstNumber(sv, OPACITY_THRESHOLD_INPUTS);
330
669
  if (opacityThreshold !== void 0) result.opacityThreshold = opacityThreshold;
331
- const metalness = firstNumber(shader, METALLIC_INPUTS);
670
+ const metalness = firstNumber(sv, METALLIC_INPUTS);
332
671
  if (metalness !== void 0) result.metalness = metalness;
333
- const roughness = firstNumber(shader, ROUGHNESS_INPUTS);
672
+ const roughness = firstNumber(sv, ROUGHNESS_INPUTS);
334
673
  if (roughness !== void 0) result.roughness = roughness;
335
- const emissive = firstColor(shader, EMISSIVE_INPUTS);
336
- if (emissive && shader.GetAttribute("inputs:enable_emission").Get() !== false) {
674
+ const emissive = firstColor(sv, EMISSIVE_INPUTS);
675
+ if (emissive && svBoolean(sv, "enable_emission") !== false) {
337
676
  result.emissiveColor = emissive;
338
- }
339
- const colorTex = findTexture(shader, TEXTURE_LOOKUPS.color);
677
+ const intensity = svNumber(sv, "emissive_intensity");
678
+ if (intensity !== void 0) result.emissiveIntensity = intensity;
679
+ }
680
+ const ior = svNumber(sv, "ior");
681
+ if (ior !== void 0) result.ior = ior;
682
+ const clearcoat = svNumber(sv, "clearcoat");
683
+ if (clearcoat !== void 0) result.clearcoat = clearcoat;
684
+ const clearcoatRoughness = svNumber(sv, "clearcoatRoughness");
685
+ if (clearcoatRoughness !== void 0) result.clearcoatRoughness = clearcoatRoughness;
686
+ if (svNumber(sv, "useSpecularWorkflow") === 1) {
687
+ const specular = svColor(sv, "specularColor");
688
+ if (specular) result.specularColor = specular;
689
+ }
690
+ const colorTex = findTexture(sv, TEXTURE_LOOKUPS.color);
340
691
  if (colorTex !== void 0) result.colorTexture = colorTex;
341
- const opacityTex = findTexture(shader, TEXTURE_LOOKUPS.opacity);
692
+ const opacityTex = findTexture(sv, TEXTURE_LOOKUPS.opacity);
342
693
  if (opacityTex !== void 0) result.opacityTexture = opacityTex;
343
- const normal = findTexture(shader, TEXTURE_LOOKUPS.normal);
694
+ const normal = findTexture(sv, TEXTURE_LOOKUPS.normal);
344
695
  if (normal !== void 0) result.normalTexture = normal;
345
- const roughTex = findTexture(shader, TEXTURE_LOOKUPS.roughness);
696
+ const roughTex = findTexture(sv, TEXTURE_LOOKUPS.roughness);
346
697
  if (roughTex !== void 0) result.roughnessTexture = roughTex;
347
- const metalTex = findTexture(shader, TEXTURE_LOOKUPS.metalness);
698
+ const metalTex = findTexture(sv, TEXTURE_LOOKUPS.metalness);
348
699
  if (metalTex !== void 0) result.metalnessTexture = metalTex;
349
- const aoTex = findTexture(shader, TEXTURE_LOOKUPS.occlusion);
700
+ const aoTex = findTexture(sv, TEXTURE_LOOKUPS.occlusion);
350
701
  if (aoTex !== void 0) result.occlusionTexture = aoTex;
351
- const emissiveTex = findTexture(shader, TEXTURE_LOOKUPS.emissive);
702
+ const emissiveTex = findTexture(sv, TEXTURE_LOOKUPS.emissive);
352
703
  if (emissiveTex !== void 0) result.emissiveTexture = emissiveTex;
704
+ const orm = directTexture(sv, "ORM_texture") ?? mdlValueTexture(sv, "ORM_texture");
705
+ if (svBoolean(sv, "enable_ORM_texture") === true && orm) {
706
+ result.occlusionTexture = { ...orm, outputChannel: "r" };
707
+ result.roughnessTexture = { ...orm, outputChannel: "g" };
708
+ result.metalnessTexture = { ...orm, outputChannel: "b" };
709
+ }
710
+ switch (mdlSource?.family) {
711
+ case "glass":
712
+ readOmniGlass(sv, result);
713
+ break;
714
+ case "clearcoat":
715
+ readOmniClearCoat(sv, result);
716
+ break;
717
+ case "surface":
718
+ readOmniSurface(sv, result);
719
+ break;
720
+ }
353
721
  return result;
354
722
  }
355
- function findTexture(shader, lookup) {
723
+ function classifyOmniMdl(name) {
724
+ if (!name) return void 0;
725
+ if (name.startsWith("OmniGlass")) return "glass";
726
+ if (name.startsWith("OmniPBR_ClearCoat")) return "clearcoat";
727
+ if (name.startsWith("OmniPBR")) return "pbr";
728
+ if (name.startsWith("OmniSurface")) return "surface";
729
+ return void 0;
730
+ }
731
+ function readMdlShaderSource(shader, provider) {
732
+ const asset = shader.GetAttribute("info:mdl:sourceAsset").Get();
733
+ if (!(asset instanceof AssetPath) || !asset.path) return void 0;
734
+ const sub = shader.GetAttribute("info:mdl:sourceAsset:subIdentifier").Get();
735
+ const stem = (asset.path.split("/").pop() ?? "").replace(/\.mdl$/i, "");
736
+ const id = typeof sub === "string" && sub.length > 0 ? sub : stem;
737
+ const decl = provider?.(asset.path)?.materials.get(id);
738
+ const family = classifyOmniMdl(decl?.base) ?? classifyOmniMdl(id) ?? classifyOmniMdl(stem);
739
+ const source = { assetPath: asset.path, id };
740
+ if (family) source.family = family;
741
+ if (decl && (decl.defaults.size > 0 || decl.args.size > 0)) {
742
+ source.values = new Map([...decl.defaults, ...decl.args]);
743
+ }
744
+ return source;
745
+ }
746
+ function readOmniGlass(sv, result) {
747
+ result.transmission = 1;
748
+ result.metalness = 0;
749
+ result.color = svColor(sv, "glass_color") ?? [1, 1, 1];
750
+ result.ior = svNumber(sv, "glass_ior") ?? 1.491;
751
+ result.roughness = svNumber(sv, "frosting_roughness") ?? 0;
752
+ const depth = svNumber(sv, "depth");
753
+ if (svBoolean(sv, "thin_walled") !== true && depth !== void 0) result.thickness = depth;
754
+ const cutout = svNumber(sv, "cutout_opacity");
755
+ if (cutout !== void 0 && cutout < 1) result.opacity = cutout;
756
+ }
757
+ function readOmniClearCoat(sv, result) {
758
+ if (svBoolean(sv, "enable_clearcoat") === false) return;
759
+ result.clearcoat = 1;
760
+ const roughness = svNumber(sv, "clearcoat_reflection_roughness");
761
+ if (roughness !== void 0) result.clearcoatRoughness = roughness;
762
+ const normal = directTexture(sv, "clearcoat_normalmap_texture") ?? mdlValueTexture(sv, "clearcoat_normalmap_texture");
763
+ if (normal && svBoolean(sv, "enable_clearcoat_normalmap_texture") !== false) {
764
+ result.clearcoatNormalTexture = normal;
765
+ }
766
+ }
767
+ function readOmniSurface(sv, result) {
768
+ const color = svColor(sv, "diffuse_reflection_color");
769
+ if (color) result.color = color;
770
+ const metalness = svNumber(sv, "metalness");
771
+ if (metalness !== void 0) result.metalness = metalness;
772
+ const roughness = svNumber(sv, "specular_reflection_roughness");
773
+ if (roughness !== void 0) result.roughness = roughness;
774
+ const ior = svNumber(sv, "specular_reflection_ior");
775
+ if (ior !== void 0) result.ior = ior;
776
+ const coat = svNumber(sv, "coat_weight");
777
+ if (coat !== void 0 && coat > 0) {
778
+ result.clearcoat = coat;
779
+ const coatRoughness = svNumber(sv, "coat_roughness");
780
+ if (coatRoughness !== void 0) result.clearcoatRoughness = coatRoughness;
781
+ }
782
+ const emissionWeight = svNumber(sv, "emission_weight");
783
+ const emissionColor = svColor(sv, "emission_color");
784
+ if (emissionWeight !== void 0 && emissionWeight > 0 && emissionColor) {
785
+ result.emissiveColor = emissionColor;
786
+ result.emissiveIntensity = emissionWeight;
787
+ }
788
+ if (svBoolean(sv, "enable_opacity") === true) {
789
+ const opacity = svNumber(sv, "geometry_opacity");
790
+ if (opacity !== void 0) result.opacity = opacity;
791
+ }
792
+ }
793
+ function authored(sv, name) {
794
+ return sv.shader.GetAttribute(`inputs:${name}`).Get();
795
+ }
796
+ function asNumber2(v) {
797
+ return typeof v === "number" ? v : void 0;
798
+ }
799
+ function asBoolean(v) {
800
+ return typeof v === "boolean" ? v : void 0;
801
+ }
802
+ function asVec(v, length) {
803
+ if (Array.isArray(v) && v.length >= length && v.every((n) => typeof n === "number")) {
804
+ return v.slice(0, length);
805
+ }
806
+ return void 0;
807
+ }
808
+ function svNumber(sv, name) {
809
+ return asNumber2(authored(sv, name)) ?? asNumber2(sv.mdl?.get(name));
810
+ }
811
+ function svBoolean(sv, name) {
812
+ return asBoolean(authored(sv, name)) ?? asBoolean(sv.mdl?.get(name));
813
+ }
814
+ function svColor(sv, name) {
815
+ const v = asVec(authored(sv, name), 3) ?? asVec(sv.mdl?.get(name), 3);
816
+ return v ? v : void 0;
817
+ }
818
+ function svVec2(sv, name) {
819
+ const v = asVec(authored(sv, name), 2) ?? asVec(sv.mdl?.get(name), 2);
820
+ return v ? v : void 0;
821
+ }
822
+ function firstNumber(sv, names) {
823
+ for (const name of names) {
824
+ const v = asNumber2(authored(sv, name));
825
+ if (v !== void 0) return v;
826
+ }
827
+ for (const name of names) {
828
+ const v = asNumber2(sv.mdl?.get(name));
829
+ if (v !== void 0) return v;
830
+ }
831
+ return void 0;
832
+ }
833
+ function firstColor(sv, names) {
834
+ for (const name of names) {
835
+ const v = asVec(authored(sv, name), 3);
836
+ if (v) return v;
837
+ }
838
+ for (const name of names) {
839
+ const v = asVec(sv.mdl?.get(name), 3);
840
+ if (v) return v;
841
+ }
842
+ return void 0;
843
+ }
844
+ function directTexture(sv, name) {
845
+ const v = authored(sv, name);
846
+ if (v instanceof AssetPath && v.path) return withMdlTransform(sv, { path: v.path });
847
+ return void 0;
848
+ }
849
+ function mdlValueTexture(sv, name) {
850
+ const v = sv.mdl?.get(name);
851
+ if (!isMdlTexture(v)) return void 0;
852
+ const texture = { path: resolveMdlRelative(sv.mdlAssetPath, v.assetPath) };
853
+ if (v.sourceColorSpace) texture.sourceColorSpace = v.sourceColorSpace;
854
+ return withMdlTransform(sv, texture);
855
+ }
856
+ function resolveMdlRelative(modulePath, path) {
857
+ if (!modulePath || path.startsWith("/") || /^[a-z][a-z0-9+.-]*:/i.test(path)) return path;
858
+ return joinPosix(modulePath, path);
859
+ }
860
+ function withMdlTransform(sv, texture) {
861
+ const transform = mdlTextureTransform(sv);
862
+ return transform ? { ...texture, transform } : texture;
863
+ }
864
+ function findTexture(sv, lookup) {
356
865
  for (const name of lookup.direct) {
357
- const v = shader.GetAttribute(name).Get();
358
- if (v instanceof AssetPath && v.path) return { path: v.path };
866
+ const texture = directTexture(sv, name);
867
+ if (texture) return texture;
359
868
  }
360
869
  for (const name of lookup.surface) {
361
- const conn = shader.GetAttribute(name).GetConnections()[0];
870
+ const conn = sv.shader.GetAttribute(`inputs:${name}`).GetConnections()[0];
362
871
  if (!conn) continue;
363
- const texPrim = shader.GetStage().GetPrimAtPath(conn.split(".")[0]);
872
+ const texPrim = sv.shader.GetStage().GetPrimAtPath(conn.split(".")[0]);
364
873
  if (!texPrim) continue;
365
874
  const file = texPrim.GetAttribute("inputs:file").Get();
366
- if (file instanceof AssetPath && file.path) return readUvTexture(texPrim, file.path);
875
+ if (file instanceof AssetPath && file.path) {
876
+ const tex = readUvTexture(texPrim, file.path);
877
+ const channel = outputChannelOf(conn);
878
+ if (channel) tex.outputChannel = channel;
879
+ return tex;
880
+ }
881
+ }
882
+ for (const name of lookup.direct) {
883
+ const texture = mdlValueTexture(sv, name);
884
+ if (texture) return texture;
367
885
  }
368
886
  return void 0;
369
887
  }
888
+ function outputChannelOf(connection) {
889
+ const m = /\.outputs:(\w+)$/.exec(connection);
890
+ switch (m?.[1]) {
891
+ case "r":
892
+ case "g":
893
+ case "b":
894
+ case "a":
895
+ return m[1];
896
+ case "rgb":
897
+ case "rgba":
898
+ return "rgb";
899
+ default:
900
+ return void 0;
901
+ }
902
+ }
903
+ function mdlTextureTransform(sv) {
904
+ const transform = {};
905
+ const translation = svVec2(sv, "texture_translate");
906
+ if (translation) transform.translation = translation;
907
+ const scale = svVec2(sv, "texture_scale");
908
+ if (scale) transform.scale = scale;
909
+ const rotation = svNumber(sv, "texture_rotate");
910
+ if (rotation !== void 0) transform.rotation = rotation;
911
+ return Object.keys(transform).length > 0 ? transform : void 0;
912
+ }
370
913
  var WRAP_VALUES = /* @__PURE__ */ new Set(["repeat", "clamp", "mirror", "black"]);
371
914
  function readUvTexture(texPrim, path) {
372
915
  const tex = { path };
@@ -378,39 +921,58 @@ function readUvTexture(texPrim, path) {
378
921
  if (scale) tex.scale = scale;
379
922
  const bias = numArray(texPrim, "inputs:bias", 4);
380
923
  if (bias) tex.bias = bias;
381
- const transform = readTransform2d(texPrim);
382
- if (transform) tex.transform = transform;
924
+ const sourceColorSpace = texPrim.GetAttribute("inputs:sourceColorSpace").Get();
925
+ if (sourceColorSpace === "raw" || sourceColorSpace === "sRGB" || sourceColorSpace === "auto") {
926
+ tex.sourceColorSpace = sourceColorSpace;
927
+ }
928
+ const st = readStChain(texPrim);
929
+ if (st.transform) tex.transform = st.transform;
930
+ if (st.uvSet) tex.uvSet = st.uvSet;
383
931
  return tex;
384
932
  }
385
- function readTransform2d(texPrim) {
386
- const conn = texPrim.GetAttribute("inputs:st").GetConnections()[0];
387
- if (!conn) return void 0;
388
- const node = texPrim.GetStage().GetPrimAtPath(conn.split(".")[0]);
389
- if (!node || node.GetAttribute("info:id").Get() !== "UsdTransform2d") return void 0;
390
- const transform = {};
391
- const translation = numArray(node, "inputs:translation", 2);
392
- if (translation) transform.translation = translation;
393
- const scale = numArray(node, "inputs:scale", 2);
394
- if (scale) transform.scale = scale;
395
- const rotation = node.GetAttribute("inputs:rotation").Get();
396
- if (typeof rotation === "number") transform.rotation = rotation;
397
- return Object.keys(transform).length > 0 ? transform : void 0;
933
+ function connectedPrim(prim, input) {
934
+ const conn = prim.GetAttribute(input).GetConnections()[0];
935
+ if (!conn) return null;
936
+ return prim.GetStage().GetPrimAtPath(conn.split(".")[0]);
398
937
  }
399
- function numArray(prim, name, length) {
400
- const v = prim.GetAttribute(name).Get();
401
- if (Array.isArray(v) && v.length >= length && v.every((n) => typeof n === "number")) {
402
- return v.slice(0, length);
938
+ function readStChain(texPrim) {
939
+ const out = {};
940
+ let node = connectedPrim(texPrim, "inputs:st");
941
+ if (node && node.GetAttribute("info:id").Get() === "UsdTransform2d") {
942
+ const transform = {};
943
+ const translation = numArray(node, "inputs:translation", 2);
944
+ if (translation) transform.translation = translation;
945
+ const scale = numArray(node, "inputs:scale", 2);
946
+ if (scale) transform.scale = scale;
947
+ const rotation = node.GetAttribute("inputs:rotation").Get();
948
+ if (typeof rotation === "number") transform.rotation = rotation;
949
+ if (Object.keys(transform).length > 0) out.transform = transform;
950
+ node = connectedPrim(node, "inputs:in");
951
+ }
952
+ if (node && node.GetAttribute("info:id").Get() === "UsdPrimvarReader_float2") {
953
+ const varname = node.GetAttribute("inputs:varname").Get();
954
+ if (typeof varname === "string" && varname.length > 0) out.uvSet = varname;
403
955
  }
404
- return void 0;
956
+ return out;
957
+ }
958
+ function numArray(prim, name, length) {
959
+ return asVec(prim.GetAttribute(name).Get(), length);
405
960
  }
406
961
  function findBinding(prim) {
962
+ let chosen;
407
963
  let p = prim;
408
964
  while (p) {
409
- const targets = p.GetRelationship("material:binding").GetTargets();
410
- if (targets.length > 0) return targets[0];
965
+ for (const name of ["material:binding:preview", "material:binding"]) {
966
+ const rel = p.GetRelationship(name);
967
+ const target = rel.GetTargets()[0];
968
+ if (!target) continue;
969
+ const stronger = rel.GetMetadata("bindMaterialAs") === "strongerThanDescendants";
970
+ if (chosen === void 0 || stronger) chosen = target;
971
+ break;
972
+ }
411
973
  p = p.GetParent();
412
974
  }
413
- return void 0;
975
+ return chosen;
414
976
  }
415
977
  function findSurfaceShader(material) {
416
978
  for (const out of SURFACE_OUTPUTS) {
@@ -423,22 +985,6 @@ function findSurfaceShader(material) {
423
985
  }
424
986
  return material.GetChildren().find((c) => c.GetTypeName() === "Shader") ?? void 0;
425
987
  }
426
- function firstColor(shader, names) {
427
- for (const name of names) {
428
- const v = shader.GetAttribute(name).Get();
429
- if (Array.isArray(v) && v.length >= 3 && v.every((n) => typeof n === "number")) {
430
- return [v[0], v[1], v[2]];
431
- }
432
- }
433
- return void 0;
434
- }
435
- function firstNumber(shader, names) {
436
- for (const name of names) {
437
- const v = shader.GetAttribute(name).Get();
438
- if (typeof v === "number") return v;
439
- }
440
- return void 0;
441
- }
442
988
 
443
989
  // src/robot/buildKinematicTree.ts
444
990
  var WORLD = "";
@@ -720,61 +1266,6 @@ function leafName(path) {
720
1266
  return parts[parts.length - 1] ?? path;
721
1267
  }
722
1268
 
723
- // src/usd/AssetResolver.ts
724
- var DefaultAssetResolver = class {
725
- resolve(assetPath, baseUrl) {
726
- try {
727
- return new URL(assetPath, baseUrl || void 0).href;
728
- } catch {
729
- return joinPosix(baseUrl, assetPath);
730
- }
731
- }
732
- async fetchText(url) {
733
- const res = await fetch(url);
734
- if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
735
- return res.text();
736
- }
737
- async fetchBytes(url) {
738
- const res = await fetch(url);
739
- if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
740
- return new Uint8Array(await res.arrayBuffer());
741
- }
742
- };
743
- function createMemoryResolver(files) {
744
- const decoder = new TextDecoder();
745
- const encoder = new TextEncoder();
746
- return {
747
- resolve(assetPath, baseUrl) {
748
- return joinPosix(baseUrl, assetPath);
749
- },
750
- fetchText(url) {
751
- const v = files[url];
752
- if (v === void 0) return Promise.reject(new Error(`asset not found: ${url}`));
753
- return Promise.resolve(typeof v === "string" ? v : decoder.decode(v));
754
- },
755
- fetchBytes(url) {
756
- const v = files[url];
757
- if (v === void 0) return Promise.reject(new Error(`asset not found: ${url}`));
758
- return Promise.resolve(typeof v === "string" ? encoder.encode(v) : v);
759
- }
760
- };
761
- }
762
- function joinPosix(baseUrl, rel) {
763
- if (rel.startsWith("/")) return normalizePosix(rel);
764
- const dir = baseUrl.slice(0, baseUrl.lastIndexOf("/") + 1);
765
- return normalizePosix(dir + rel);
766
- }
767
- function normalizePosix(path) {
768
- const isAbsolute = path.startsWith("/");
769
- const out = [];
770
- for (const part of path.split("/")) {
771
- if (part === "" || part === ".") continue;
772
- if (part === "..") out.pop();
773
- else out.push(part);
774
- }
775
- return (isAbsolute ? "/" : "") + out.join("/");
776
- }
777
-
778
1269
  // src/parser/reader.ts
779
1270
  var ParseError = class extends Error {
780
1271
  constructor(message, line, col) {
@@ -861,7 +1352,7 @@ var TokenizeError = class extends Error {
861
1352
  };
862
1353
  var IDENT_START = /[A-Za-z_]/;
863
1354
  var IDENT_CONT = /[A-Za-z0-9_:]/;
864
- var NUMBER_RE = /^[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?/;
1355
+ var NUMBER_RE2 = /^[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?/;
865
1356
  var INF_NAN_RE = /^[-+]?(?:inf|nan)\b/i;
866
1357
  function tokenize(src) {
867
1358
  const tokens = [];
@@ -933,7 +1424,7 @@ function tokenize(src) {
933
1424
  continue;
934
1425
  }
935
1426
  if (/[0-9]/.test(c) || (c === "-" || c === "+" || c === ".") && /[0-9.]/.test(src[i + 1] ?? "")) {
936
- const m = NUMBER_RE.exec(src.slice(i));
1427
+ const m = NUMBER_RE2.exec(src.slice(i));
937
1428
  if (m) {
938
1429
  const text = m[0];
939
1430
  push("number", text, startCol, Number(text));
@@ -1776,6 +2267,10 @@ var Attribute = class {
1776
2267
  GetConnections() {
1777
2268
  return this._spec?.connections ?? [];
1778
2269
  }
2270
+ /** Authored attribute metadata (`interpolation`, `elementSize`, …). */
2271
+ GetMetadata(key) {
2272
+ return this._spec?.metadata[key];
2273
+ }
1779
2274
  };
1780
2275
  var Relationship = class {
1781
2276
  constructor(_prim, _name, _spec) {
@@ -1807,6 +2302,10 @@ var Relationship = class {
1807
2302
  GetTargets() {
1808
2303
  return this._spec?.targets ?? [];
1809
2304
  }
2305
+ /** Authored relationship metadata (`bindMaterialAs`, …). */
2306
+ GetMetadata(key) {
2307
+ return this._spec?.metadata[key];
2308
+ }
1810
2309
  };
1811
2310
 
1812
2311
  // src/usd/Prim.ts
@@ -2159,10 +2658,17 @@ var CrateType = {
2159
2658
  Quatf: 17,
2160
2659
  Vec2d: 19,
2161
2660
  Vec2f: 20,
2661
+ Vec2h: 21,
2662
+ Vec2i: 22,
2162
2663
  Vec3d: 23,
2163
2664
  Vec3f: 24,
2665
+ Vec3h: 25,
2666
+ Vec3i: 26,
2164
2667
  Vec4d: 27,
2165
2668
  Vec4f: 28,
2669
+ Vec4h: 29,
2670
+ Vec4i: 30,
2671
+ Dictionary: 31,
2166
2672
  TokenListOp: 32,
2167
2673
  PathListOp: 34,
2168
2674
  ReferenceListOp: 35,
@@ -2173,6 +2679,8 @@ var CrateType = {
2173
2679
  Permission: 43,
2174
2680
  Variability: 44,
2175
2681
  VariantSelectionMap: 45,
2682
+ TimeSamples: 46,
2683
+ DoubleVector: 48,
2176
2684
  StringVector: 50,
2177
2685
  PayloadListOp: 55};
2178
2686
  var ListOpBits = {
@@ -2207,6 +2715,12 @@ function halfToFloat(h) {
2207
2715
  var MAGIC = "PXR-USDC";
2208
2716
  var scratch = new DataView(new ArrayBuffer(8));
2209
2717
  var FIELDSET_END = -1;
2718
+ var MIN_COMPRESSED_ARRAY_SIZE = 16;
2719
+ function inlineInt8s(low, n) {
2720
+ const out = new Array(n);
2721
+ for (let i = 0; i < n; i++) out[i] = (low >>> i * 8 & 255) << 24 >> 24;
2722
+ return out;
2723
+ }
2210
2724
  var CrateReader = class {
2211
2725
  version;
2212
2726
  view;
@@ -2440,6 +2954,33 @@ var CrateReader = class {
2440
2954
  if (b.isInlined) return this.readInlined(b.type, b.payload);
2441
2955
  return this.readScalar(b.type, Number(b.payload));
2442
2956
  }
2957
+ /**
2958
+ * Decode a `timeSamples` field (a {@link CrateType.TimeSamples} rep) into
2959
+ * parallel times/values arrays; `undefined` if `rep` is some other type.
2960
+ *
2961
+ * Layout (pxr `crateFile.cpp`, `Write(TimeSamples)`): an `int64` offset —
2962
+ * relative to its own position — jumps over the recursively-written times
2963
+ * data to the times `ValueRep` (a `DoubleVector`); a second such offset
2964
+ * jumps over the samples' data to `[u64 count][count × ValueRep]`. Sample
2965
+ * reps decode through {@link getValue}, so every scalar/array type works.
2966
+ */
2967
+ getTimeSamples(rep) {
2968
+ const b = decodeRepBits(rep);
2969
+ if (b.type !== CrateType.TimeSamples || b.isArray || b.isInlined) return void 0;
2970
+ const off = Number(b.payload);
2971
+ let p = off + Number(this.i64(off));
2972
+ const times = this.getValue(this.view.getBigUint64(p, true));
2973
+ p += 8;
2974
+ if (!Array.isArray(times) || !times.every((t) => typeof t === "number")) return void 0;
2975
+ p += Number(this.i64(p));
2976
+ const count = this.u64(p);
2977
+ p += 8;
2978
+ const values = new Array(count);
2979
+ for (let i = 0; i < count; i++) {
2980
+ values[i] = this.getValue(this.view.getBigUint64(p + i * 8, true));
2981
+ }
2982
+ return { times, values };
2983
+ }
2443
2984
  readInlined(type, payload) {
2444
2985
  const low = Number(payload & 0xffffffffn);
2445
2986
  switch (type) {
@@ -2469,6 +3010,62 @@ var CrateReader = class {
2469
3010
  case CrateType.Permission:
2470
3011
  case CrateType.Variability:
2471
3012
  return low;
3013
+ // Vectors whose components are all small integers are inlined as one
3014
+ // int8 per component in the payload's low bytes (crateValueInliners.h).
3015
+ case CrateType.Vec2i:
3016
+ case CrateType.Vec2h:
3017
+ case CrateType.Vec2f:
3018
+ case CrateType.Vec2d:
3019
+ return inlineInt8s(low, 2);
3020
+ case CrateType.Vec3i:
3021
+ case CrateType.Vec3h:
3022
+ case CrateType.Vec3f:
3023
+ case CrateType.Vec3d:
3024
+ return inlineInt8s(low, 3);
3025
+ case CrateType.Vec4i:
3026
+ case CrateType.Vec4h:
3027
+ case CrateType.Vec4f:
3028
+ case CrateType.Vec4d:
3029
+ return inlineInt8s(low, 4);
3030
+ // Matrices inline when off-diagonal is zero and the diagonal fits int8.
3031
+ case CrateType.Matrix3d: {
3032
+ const [a, b, c] = inlineInt8s(low, 3);
3033
+ return new UsdMatrix([
3034
+ a,
3035
+ 0,
3036
+ 0,
3037
+ 0,
3038
+ b,
3039
+ 0,
3040
+ 0,
3041
+ 0,
3042
+ c
3043
+ ], 3);
3044
+ }
3045
+ case CrateType.Matrix4d: {
3046
+ const [a, b, c, d] = inlineInt8s(low, 4);
3047
+ return new UsdMatrix([
3048
+ a,
3049
+ 0,
3050
+ 0,
3051
+ 0,
3052
+ 0,
3053
+ b,
3054
+ 0,
3055
+ 0,
3056
+ 0,
3057
+ 0,
3058
+ c,
3059
+ 0,
3060
+ 0,
3061
+ 0,
3062
+ 0,
3063
+ d
3064
+ ], 4);
3065
+ }
3066
+ // Only the empty dictionary is inlined.
3067
+ case CrateType.Dictionary:
3068
+ return {};
2472
3069
  default:
2473
3070
  return void 0;
2474
3071
  }
@@ -2486,6 +3083,12 @@ var CrateReader = class {
2486
3083
  return v.getInt32(off, true);
2487
3084
  case CrateType.UInt:
2488
3085
  return v.getUint32(off, true);
3086
+ case CrateType.UChar:
3087
+ return v.getUint8(off);
3088
+ case CrateType.Int64:
3089
+ return Number(v.getBigInt64(off, true));
3090
+ case CrateType.UInt64:
3091
+ return Number(v.getBigUint64(off, true));
2489
3092
  case CrateType.Token:
2490
3093
  return this.getToken(v.getUint32(off, true));
2491
3094
  case CrateType.String:
@@ -2504,6 +3107,18 @@ var CrateReader = class {
2504
3107
  return this.readFloat64s(off, 3);
2505
3108
  case CrateType.Vec4d:
2506
3109
  return this.readFloat64s(off, 4);
3110
+ case CrateType.Vec2h:
3111
+ return this.readHalfs(off, 2);
3112
+ case CrateType.Vec3h:
3113
+ return this.readHalfs(off, 3);
3114
+ case CrateType.Vec4h:
3115
+ return this.readHalfs(off, 4);
3116
+ case CrateType.Vec2i:
3117
+ return this.readInt32s(off, 2);
3118
+ case CrateType.Vec3i:
3119
+ return this.readInt32s(off, 3);
3120
+ case CrateType.Vec4i:
3121
+ return this.readInt32s(off, 4);
2507
3122
  case CrateType.Quatf: {
2508
3123
  const q = this.readFloat32s(off, 4);
2509
3124
  return new Quat(q[3], [q[0], q[1], q[2]]);
@@ -2533,41 +3148,176 @@ var CrateReader = class {
2533
3148
  return this.readIndexVector(off, "string").items;
2534
3149
  case CrateType.VariantSelectionMap:
2535
3150
  return this.readVariantSelectionMap(off);
3151
+ case CrateType.DoubleVector: {
3152
+ const count = this.u64(off);
3153
+ return this.readFloat64s(off + 8, count);
3154
+ }
3155
+ case CrateType.Dictionary:
3156
+ return this.readDictionary(off, 0);
2536
3157
  default:
2537
3158
  return void 0;
2538
3159
  }
2539
3160
  }
3161
+ /** Array headers store a u32 count before crate 0.7.0, a u64 from 0.7.0 on. */
3162
+ arrayHeader(off) {
3163
+ if (this.version[0] === 0 && this.version[1] < 7) {
3164
+ return { count: this.view.getUint32(off, true), next: off + 4 };
3165
+ }
3166
+ return { count: this.u64(off), next: off + 8 };
3167
+ }
2540
3168
  readArray(type, off, compressed) {
2541
3169
  if (off === 0) return [];
2542
- const count = this.u64(off);
2543
- let p = off + 8;
2544
- if (compressed) {
2545
- const compressedSize = this.u64(p);
2546
- p += 8;
2547
- return decodeIntegers32(this.bytes.subarray(p, p + compressedSize), count);
2548
- }
3170
+ const { count, next: p } = this.arrayHeader(off);
3171
+ if (count === 0) return [];
3172
+ if (compressed) return this.readCompressedArray(type, p, count);
2549
3173
  const v = this.view;
2550
3174
  switch (type) {
3175
+ case CrateType.Bool: {
3176
+ const out = new Array(count);
3177
+ for (let i = 0; i < count; i++) out[i] = this.bytes[p + i] !== 0;
3178
+ return out;
3179
+ }
3180
+ case CrateType.UChar: {
3181
+ const out = new Array(count);
3182
+ for (let i = 0; i < count; i++) out[i] = this.bytes[p + i];
3183
+ return out;
3184
+ }
2551
3185
  case CrateType.Int:
2552
3186
  case CrateType.UInt: {
2553
3187
  const out = new Array(count);
2554
3188
  for (let i = 0; i < count; i++) out[i] = v.getInt32(p + i * 4, true);
2555
3189
  return out;
2556
3190
  }
2557
- case CrateType.Float: {
3191
+ case CrateType.Int64: {
2558
3192
  const out = new Array(count);
2559
- for (let i = 0; i < count; i++) out[i] = v.getFloat32(p + i * 4, true);
3193
+ for (let i = 0; i < count; i++) out[i] = Number(v.getBigInt64(p + i * 8, true));
2560
3194
  return out;
2561
3195
  }
3196
+ case CrateType.UInt64: {
3197
+ const out = new Array(count);
3198
+ for (let i = 0; i < count; i++) out[i] = Number(v.getBigUint64(p + i * 8, true));
3199
+ return out;
3200
+ }
3201
+ case CrateType.Half:
3202
+ return this.readHalfs(p, count);
3203
+ case CrateType.Float:
3204
+ return this.readFloat32s(p, count);
3205
+ case CrateType.Double:
3206
+ return this.readFloat64s(p, count);
2562
3207
  case CrateType.Token: {
2563
3208
  const out = new Array(count);
2564
3209
  for (let i = 0; i < count; i++) out[i] = this.getToken(v.getUint32(p + i * 4, true));
2565
3210
  return out;
2566
3211
  }
3212
+ case CrateType.String: {
3213
+ const out = new Array(count);
3214
+ for (let i = 0; i < count; i++) {
3215
+ out[i] = this.getToken(this.getStrings()[v.getUint32(p + i * 4, true)] ?? 0);
3216
+ }
3217
+ return out;
3218
+ }
3219
+ case CrateType.AssetPath: {
3220
+ const out = new Array(count);
3221
+ for (let i = 0; i < count; i++) {
3222
+ out[i] = new AssetPath(
3223
+ this.getToken(this.getStrings()[v.getUint32(p + i * 4, true)] ?? 0)
3224
+ );
3225
+ }
3226
+ return out;
3227
+ }
3228
+ case CrateType.Vec2f:
3229
+ return this.readTupleArray(p, count, 2, "f32");
2567
3230
  case CrateType.Vec3f:
2568
- return this.readVec3fArray(p, count, false);
3231
+ return this.readTupleArray(p, count, 3, "f32");
3232
+ case CrateType.Vec4f:
3233
+ return this.readTupleArray(p, count, 4, "f32");
3234
+ case CrateType.Vec2d:
3235
+ return this.readTupleArray(p, count, 2, "f64");
2569
3236
  case CrateType.Vec3d:
2570
- return this.readVec3fArray(p, count, true);
3237
+ return this.readTupleArray(p, count, 3, "f64");
3238
+ case CrateType.Vec4d:
3239
+ return this.readTupleArray(p, count, 4, "f64");
3240
+ case CrateType.Vec2h:
3241
+ return this.readTupleArray(p, count, 2, "f16");
3242
+ case CrateType.Vec3h:
3243
+ return this.readTupleArray(p, count, 3, "f16");
3244
+ case CrateType.Vec4h:
3245
+ return this.readTupleArray(p, count, 4, "f16");
3246
+ case CrateType.Vec2i:
3247
+ return this.readTupleArray(p, count, 2, "i32");
3248
+ case CrateType.Vec3i:
3249
+ return this.readTupleArray(p, count, 3, "i32");
3250
+ case CrateType.Vec4i:
3251
+ return this.readTupleArray(p, count, 4, "i32");
3252
+ case CrateType.Quatf: {
3253
+ const out = new Array(count);
3254
+ for (let i = 0; i < count; i++) {
3255
+ const q = this.readFloat32s(p + i * 16, 4);
3256
+ out[i] = new Quat(q[3], [q[0], q[1], q[2]]);
3257
+ }
3258
+ return out;
3259
+ }
3260
+ case CrateType.Quatd: {
3261
+ const out = new Array(count);
3262
+ for (let i = 0; i < count; i++) {
3263
+ const q = this.readFloat64s(p + i * 32, 4);
3264
+ out[i] = new Quat(q[3], [q[0], q[1], q[2]]);
3265
+ }
3266
+ return out;
3267
+ }
3268
+ case CrateType.Matrix3d: {
3269
+ const out = new Array(count);
3270
+ for (let i = 0; i < count; i++) out[i] = new UsdMatrix(this.readFloat64s(p + i * 72, 9), 3);
3271
+ return out;
3272
+ }
3273
+ case CrateType.Matrix4d: {
3274
+ const out = new Array(count);
3275
+ for (let i = 0; i < count; i++)
3276
+ out[i] = new UsdMatrix(this.readFloat64s(p + i * 128, 16), 4);
3277
+ return out;
3278
+ }
3279
+ default:
3280
+ return void 0;
3281
+ }
3282
+ }
3283
+ /**
3284
+ * Decode an array whose rep has the compressed bit. Int arrays are
3285
+ * integer-compressed; half/float/double arrays (crate 0.6.0+) carry a code
3286
+ * byte — `'i'` when every value is integral, `'t'` for a lookup table +
3287
+ * compressed indexes. Arrays under {@link MIN_COMPRESSED_ARRAY_SIZE} elements
3288
+ * are stored raw even when the bit is set (mirrors pxr's writer).
3289
+ */
3290
+ readCompressedArray(type, start, count) {
3291
+ let p = start;
3292
+ switch (type) {
3293
+ case CrateType.Int:
3294
+ case CrateType.UInt: {
3295
+ if (count < MIN_COMPRESSED_ARRAY_SIZE) {
3296
+ const out = new Array(count);
3297
+ for (let i = 0; i < count; i++) out[i] = this.view.getInt32(p + i * 4, true);
3298
+ return out;
3299
+ }
3300
+ return this.readCompressedInts(p, count).values;
3301
+ }
3302
+ case CrateType.Half:
3303
+ case CrateType.Float:
3304
+ case CrateType.Double: {
3305
+ const readRaw = (off, n) => type === CrateType.Double ? this.readFloat64s(off, n) : type === CrateType.Float ? this.readFloat32s(off, n) : this.readHalfs(off, n);
3306
+ if (count < MIN_COMPRESSED_ARRAY_SIZE) return readRaw(p, count);
3307
+ const code = this.bytes[p];
3308
+ p += 1;
3309
+ if (code === 105) {
3310
+ return this.readCompressedInts(p, count).values;
3311
+ }
3312
+ if (code === 116) {
3313
+ const lutSize = this.view.getUint32(p, true);
3314
+ p += 4;
3315
+ const lut = readRaw(p, lutSize);
3316
+ p += lutSize * (type === CrateType.Double ? 8 : type === CrateType.Float ? 4 : 2);
3317
+ return this.readCompressedInts(p, count).values.map((i) => lut[i] ?? 0);
3318
+ }
3319
+ return void 0;
3320
+ }
2571
3321
  default:
2572
3322
  return void 0;
2573
3323
  }
@@ -2582,20 +3332,45 @@ var CrateReader = class {
2582
3332
  for (let i = 0; i < n; i++) out[i] = this.view.getFloat64(off + i * 8, true);
2583
3333
  return out;
2584
3334
  }
2585
- readVec3fArray(off, count, double) {
3335
+ readHalfs(off, n) {
3336
+ const out = new Array(n);
3337
+ for (let i = 0; i < n; i++) out[i] = halfToFloat(this.view.getUint16(off + i * 2, true));
3338
+ return out;
3339
+ }
3340
+ readInt32s(off, n) {
3341
+ const out = new Array(n);
3342
+ for (let i = 0; i < n; i++) out[i] = this.view.getInt32(off + i * 4, true);
3343
+ return out;
3344
+ }
3345
+ /** Read `count` fixed-size `n`-tuples (vec2/3/4 of the given element kind). */
3346
+ readTupleArray(off, count, n, kind) {
3347
+ const elemSize = kind === "f64" ? 8 : kind === "f16" ? 2 : 4;
2586
3348
  const out = new Array(count);
2587
- const stride = double ? 24 : 12;
2588
3349
  for (let i = 0; i < count; i++) {
2589
- const o = off + i * stride;
2590
- out[i] = double ? [
2591
- this.view.getFloat64(o, true),
2592
- this.view.getFloat64(o + 8, true),
2593
- this.view.getFloat64(o + 16, true)
2594
- ] : [
2595
- this.view.getFloat32(o, true),
2596
- this.view.getFloat32(o + 4, true),
2597
- this.view.getFloat32(o + 8, true)
2598
- ];
3350
+ const o = off + i * n * elemSize;
3351
+ out[i] = kind === "f64" ? this.readFloat64s(o, n) : kind === "f32" ? this.readFloat32s(o, n) : kind === "f16" ? this.readHalfs(o, n) : this.readInt32s(o, n);
3352
+ }
3353
+ return out;
3354
+ }
3355
+ /**
3356
+ * Read a `VtDictionary`: `[u64 count]`, then per entry a string index (key)
3357
+ * followed by a recursive VtValue — an `int64` offset (relative to its own
3358
+ * position) over the value's data to an 8-byte `ValueRep`.
3359
+ */
3360
+ readDictionary(off, depth) {
3361
+ const out = {};
3362
+ if (depth > 16) return out;
3363
+ const count = this.u64(off);
3364
+ let p = off + 8;
3365
+ for (let i = 0; i < count; i++) {
3366
+ const key = this.getToken(this.getStrings()[this.view.getUint32(p, true)] ?? 0);
3367
+ p += 4;
3368
+ const repPos = p + Number(this.i64(p));
3369
+ const rep = this.view.getBigUint64(repPos, true);
3370
+ const b = decodeRepBits(rep);
3371
+ const value = b.type === CrateType.Dictionary && !b.isInlined && !b.isArray ? this.readDictionary(Number(b.payload), depth + 1) : this.getValue(rep);
3372
+ if (key && value !== void 0) out[key] = value;
3373
+ p = repPos + 8;
2599
3374
  }
2600
3375
  return out;
2601
3376
  }
@@ -2750,7 +3525,7 @@ function crateToUsdaFile(crate) {
2750
3525
  if (spec.specType !== SPEC_PRIM) continue;
2751
3526
  const fm = fieldsOf(spec.fieldSetIndex);
2752
3527
  primByPath.set(path, {
2753
- specifier: SPECIFIERS2[asNumber2(crate, fm.get("specifier")) ?? 0] ?? "def",
3528
+ specifier: SPECIFIERS2[asNumber3(crate, fm.get("specifier")) ?? 0] ?? "def",
2754
3529
  typeName: asString(crate, fm.get("typeName")) ?? "",
2755
3530
  name: leaf(path),
2756
3531
  metadata: buildPrimMetadata(crate, fm),
@@ -2798,13 +3573,14 @@ function buildAttribute(crate, name, fm) {
2798
3573
  const defaultRep = fm.get("default");
2799
3574
  const rawType = asString(crate, fm.get("typeName")) ?? "";
2800
3575
  const isArrayType = rawType.endsWith("[]");
3576
+ const customRep = fm.get("custom");
2801
3577
  const attr = {
2802
3578
  kind: "attribute",
2803
3579
  name,
2804
3580
  typeName: isArrayType ? rawType.slice(0, -2) : rawType,
2805
3581
  isArray: isArrayType || (defaultRep !== void 0 ? decodeRepBits(defaultRep).isArray : false),
2806
- variability: asNumber2(crate, fm.get("variability")) === 1 ? "uniform" : "varying",
2807
- custom: false,
3582
+ variability: asNumber3(crate, fm.get("variability")) === 1 ? "uniform" : "varying",
3583
+ custom: customRep !== void 0 && crate.getValue(customRep) === true,
2808
3584
  metadata: {},
2809
3585
  line: 0
2810
3586
  };
@@ -2812,6 +3588,25 @@ function buildAttribute(crate, name, fm) {
2812
3588
  const value = crate.getValue(defaultRep);
2813
3589
  if (value !== void 0) attr.value = value;
2814
3590
  }
3591
+ const connections = fm.has("connectionPaths") ? crate.getValue(fm.get("connectionPaths")) : void 0;
3592
+ if (Array.isArray(connections)) {
3593
+ const paths = connections.filter((c) => typeof c === "string" && c.length > 0);
3594
+ if (paths.length > 0) attr.connections = paths;
3595
+ }
3596
+ const interpolation = asString(crate, fm.get("interpolation"));
3597
+ if (interpolation !== void 0) attr.metadata.interpolation = interpolation;
3598
+ const tsRep = fm.get("timeSamples");
3599
+ if (tsRep !== void 0) {
3600
+ const ts = crate.getTimeSamples(tsRep);
3601
+ if (ts) {
3602
+ const samples = /* @__PURE__ */ new Map();
3603
+ const pairs = ts.times.map((t, i) => [t, ts.values[i]]).sort((a, b) => a[0] - b[0]);
3604
+ for (const [t, v] of pairs) {
3605
+ if (v !== void 0) samples.set(t, v);
3606
+ }
3607
+ if (samples.size > 0) attr.timeSamples = samples;
3608
+ }
3609
+ }
2815
3610
  return attr;
2816
3611
  }
2817
3612
  function buildRelationship(crate, name, fm) {
@@ -2856,8 +3651,16 @@ function buildLayerMetadata(crate, fm) {
2856
3651
  if (upAxis !== void 0) meta.upAxis = upAxis;
2857
3652
  const defaultPrim2 = asString(crate, fm.get("defaultPrim"));
2858
3653
  if (defaultPrim2 !== void 0) meta.defaultPrim = defaultPrim2;
2859
- const metersPerUnit = asNumber2(crate, fm.get("metersPerUnit"));
3654
+ const metersPerUnit = asNumber3(crate, fm.get("metersPerUnit"));
2860
3655
  if (metersPerUnit !== void 0) meta.metersPerUnit = metersPerUnit;
3656
+ for (const key of ["startTimeCode", "endTimeCode", "timeCodesPerSecond", "framesPerSecond"]) {
3657
+ const value = asNumber3(crate, fm.get(key));
3658
+ if (value !== void 0) meta[key] = value;
3659
+ }
3660
+ const customLayerData = fm.has("customLayerData") ? crate.getValue(fm.get("customLayerData")) : void 0;
3661
+ if (customLayerData && typeof customLayerData === "object" && !Array.isArray(customLayerData)) {
3662
+ meta.customLayerData = customLayerData;
3663
+ }
2861
3664
  return meta;
2862
3665
  }
2863
3666
  function asString(crate, rep) {
@@ -2865,7 +3668,7 @@ function asString(crate, rep) {
2865
3668
  const v = crate.getValue(rep);
2866
3669
  return typeof v === "string" ? v : void 0;
2867
3670
  }
2868
- function asNumber2(crate, rep) {
3671
+ function asNumber3(crate, rep) {
2869
3672
  if (rep === void 0) return void 0;
2870
3673
  const v = crate.getValue(rep);
2871
3674
  return typeof v === "number" ? v : void 0;
@@ -3182,6 +3985,33 @@ function stripKeys(meta, keys) {
3182
3985
  }
3183
3986
  return out;
3184
3987
  }
3988
+
3989
+ // src/usd/mdl/loadMdlModules.ts
3990
+ function collectMdlAssetPaths(stage) {
3991
+ const paths = /* @__PURE__ */ new Set();
3992
+ for (const prim of stage.Traverse()) {
3993
+ if (prim.GetTypeName() !== "Shader") continue;
3994
+ const asset = prim.GetAttribute("info:mdl:sourceAsset").Get();
3995
+ if (asset instanceof AssetPath && asset.path) paths.add(asset.path);
3996
+ }
3997
+ return [...paths];
3998
+ }
3999
+ async function loadMdlModules(stage, resolver, baseUrl) {
4000
+ const paths = collectMdlAssetPaths(stage);
4001
+ if (paths.length === 0) return void 0;
4002
+ const modules = /* @__PURE__ */ new Map();
4003
+ await Promise.all(
4004
+ paths.map(async (path) => {
4005
+ try {
4006
+ const module = parseMdl(await resolver.fetchText(resolver.resolve(path, baseUrl)));
4007
+ if (module.materials.size > 0) modules.set(path, module);
4008
+ } catch {
4009
+ }
4010
+ })
4011
+ );
4012
+ if (modules.size === 0) return void 0;
4013
+ return (assetPath) => modules.get(assetPath);
4014
+ }
3185
4015
  var USD_ENTRY = /\.(usda|usdc|usd)$/i;
3186
4016
  function isZip(bytes) {
3187
4017
  if (bytes.length < 4 || bytes[0] !== 80 || bytes[1] !== 75) return false;
@@ -3218,6 +4048,6 @@ function openUsdz(bytes) {
3218
4048
  return { rootEntry, resolver };
3219
4049
  }
3220
4050
 
3221
- export { ARTICULATION_ROOT_API, Attribute, COLLISION_API, CrateReader, DEFAULT_METERS_PER_UNIT, DefaultAssetResolver, Layer, MASS_API, MESH_COLLISION_API, PHYSICS_MATERIAL_API, ParseError, Prim, RIGID_BODY_API, Relationship, Stage, TokenizeError, buildKinematicTree, composeFile, composeLayer, computeLocalTransform, computeWorldTransform, crateToUsdaFile, createMemoryResolver, driveKindFor, extractRobotDescription, gatherGprimDescendants, gatherMeshDescendants, getJointAxis, getJointBodies, getJointDrive, getJointLimits, getJointLocalFrame, getJointStatePosition, getJointType, getMassProperties, getMaterialSubsets, hasArticulationRootAPI, hasCollisionAPI, hasRigidBodyAPI, isMesh, isNonVisualPurpose, isRenderableGprim, isScope, isSolidGprim, isXform, isZip, iterDescendants, joinPosix, jointValueFromSI, jointValueToSI, normalizeJointLimits, openUsdz, parseOpType, parseUsda, refineJointType, resolveBoundMaterial, serializeUsda, toBytes, tokenize };
3222
- //# sourceMappingURL=chunk-2UD32EGU.js.map
3223
- //# sourceMappingURL=chunk-2UD32EGU.js.map
4051
+ export { ARTICULATION_ROOT_API, Attribute, COLLISION_API, CrateReader, DEFAULT_METERS_PER_UNIT, DefaultAssetResolver, Layer, MASS_API, MESH_COLLISION_API, PHYSICS_MATERIAL_API, ParseError, Prim, RIGID_BODY_API, Relationship, Stage, TokenizeError, buildKinematicTree, collectMdlAssetPaths, composeFile, composeLayer, computeLocalTransform, computeWorldTransform, crateToUsdaFile, createMemoryResolver, driveKindFor, extractRobotDescription, gatherGprimDescendants, gatherMeshDescendants, getJointAxis, getJointBodies, getJointDrive, getJointLimits, getJointLocalFrame, getJointStatePosition, getJointType, getMassProperties, getMaterialSubsets, hasArticulationRootAPI, hasCollisionAPI, hasRigidBodyAPI, isBasisCurves, isMdlTexture, isMesh, isNonVisualPurpose, isPoints, isRenderableGprim, isScope, isSolidGprim, isUnsupportedGprim, isXform, isZip, iterDescendants, joinPosix, jointValueFromSI, jointValueToSI, loadMdlModules, normalizeJointLimits, openUsdz, parseMdl, parseMdlLiteral, parseOpType, parseUsda, refineJointType, resolveBoundMaterial, serializeUsda, toBytes, tokenize };
4052
+ //# sourceMappingURL=chunk-AXPMXEQC.js.map
4053
+ //# sourceMappingURL=chunk-AXPMXEQC.js.map