rayzee 11.2.0 → 11.3.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.
Files changed (63) hide show
  1. package/README.md +62 -33
  2. package/dist/ArchiveImporter-D735xX-4.js +7860 -0
  3. package/dist/BidirectionalIntegrator-M89c0AlP.js +954 -0
  4. package/dist/{BufferLayout-D_IBo2ci.js → BufferLayout-xPRH9jYD.js} +41 -5
  5. package/dist/{NeuralRetouch-DFGbnmLb.js → NeuralRetouch-DiBH63kz.js} +1 -1
  6. package/dist/{NeuralSuperRes-BtXvyJQl.js → NeuralSuperRes-CZNQP13W.js} +1 -1
  7. package/dist/{PathTracer-BHXGJtPN.js → PathTracer-BXCCVrPK.js} +4371 -4612
  8. package/dist/{PhysicalSky-DN6u8UX4.js → PhysicalSky-DqmaS0lb.js} +2 -2
  9. package/dist/{RayzeeRenderer-Dw1x8mVL.js → RayzeeRenderer-DUSMFhmc.js} +426 -363
  10. package/dist/SolarLimb-bZE6y63S.js +762 -0
  11. package/dist/addons/archives.es.js +1 -1
  12. package/dist/addons/bidirectional.es.js +1 -1
  13. package/dist/addons/physical-sky.es.js +1 -1
  14. package/dist/rayzee-core.es.js +7 -7
  15. package/dist/rayzee.es.js +472 -468
  16. package/dist/rayzee.umd.js +106 -105
  17. package/dist/sceneCachePolicy-BAib5fCp.js +1602 -0
  18. package/package.json +1 -1
  19. package/src/EngineDefaults.js +1 -1
  20. package/src/PathTracerApp.js +4 -3
  21. package/src/Processor/ArchiveImporter.js +173 -94
  22. package/src/Processor/ArchiveReader.js +20 -23
  23. package/src/Processor/AssetLoader.js +48 -1
  24. package/src/Processor/BVHRefitter.js +109 -13
  25. package/src/Processor/BufferLayout.js +115 -0
  26. package/src/Processor/ChunkedRecords.js +3 -2
  27. package/src/Processor/EmissiveTriangleBuilder.js +6 -6
  28. package/src/Processor/GeometryExtractor.js +189 -79
  29. package/src/Processor/HostMemory.js +39 -9
  30. package/src/Processor/InstanceTable.js +714 -42
  31. package/src/Processor/PBRT/PBRTCurves.js +224 -6
  32. package/src/Processor/PBRT/PBRTMaterials.js +3 -0
  33. package/src/Processor/PBRT/PBRTSceneBuilder.js +82 -25
  34. package/src/Processor/PackedRayBuffer.js +5 -2
  35. package/src/Processor/SceneProcessor.js +747 -141
  36. package/src/Processor/TLASBuilder.js +32 -17
  37. package/src/Processor/USD/USDLayer.js +1149 -0
  38. package/src/Processor/USD/USDScene.js +1655 -0
  39. package/src/Processor/USD/USDStage.js +682 -0
  40. package/src/Processor/USD/USDText.js +674 -0
  41. package/src/Processor/USD/index.js +138 -0
  42. package/src/Processor/Workers/BVHRefitWorker.js +3 -3
  43. package/src/RayzeeRenderer.js +168 -27
  44. package/src/Stages/NormalDepth.js +7 -12
  45. package/src/Stages/PathTracer.js +12 -17
  46. package/src/Stages/PathTracerStage.js +273 -96
  47. package/src/Storage/GeometrySpill.js +46 -14
  48. package/src/Storage/SceneGraphCodec.js +17 -3
  49. package/src/Storage/SpillStore.js +9 -0
  50. package/src/TSL/BVHTraversal.js +183 -7
  51. package/src/TSL/Common.js +57 -13
  52. package/src/TSL/ShadeKernel.js +3 -2
  53. package/src/TSL/TextureSampling.js +11 -8
  54. package/src/TSL/patches.js +84 -0
  55. package/src/integrators/BidirectionalIntegrator.js +20 -2
  56. package/src/managers/DenoisingManager.js +4 -4
  57. package/src/managers/InteractionManager.js +19 -6
  58. package/src/managers/MaterialDataManager.js +22 -5
  59. package/src/managers/UniformManager.js +3 -0
  60. package/dist/ArchiveImporter-eNlu0_6F.js +0 -5198
  61. package/dist/BidirectionalIntegrator-D1-6UySB.js +0 -946
  62. package/dist/SolarLimb-CPaeZVwz.js +0 -721
  63. package/dist/sceneCachePolicy-DA7iGoL4.js +0 -485
@@ -0,0 +1,1149 @@
1
+ /**
2
+ * A USD layer in one shape for both file formats: a tree of prim specs, each with its specifier, metadata,
3
+ * composition arcs (as list ops), variant sets and properties. USDText.js fills it from .usda, parseUSDC from crate
4
+ * (.usdc) files.
5
+ */
6
+
7
+ /** A reference or payload: `@asset@<path>`; `asset` is empty for one inside the same layer stack. */
8
+ export class Ref {
9
+
10
+ constructor( asset, path ) {
11
+
12
+ this.asset = asset;
13
+ this.path = path;
14
+
15
+ }
16
+
17
+ }
18
+
19
+ export const listOp = () => ( { explicit: null, prepend: [], append: [], add: [], delete: [] } );
20
+
21
+ const itemKey = item => ( item instanceof Ref ? `${item.asset}\u0000${item.path}` : String( item ) );
22
+
23
+ /** List ops, given strongest first, applied weakest first; each item's `source` is its op's entry in `sources`. */
24
+ export function composeListOps( ops, sources = null ) {
25
+
26
+ let items = [];
27
+ for ( let k = ops.length - 1; k >= 0; k -- ) {
28
+
29
+ const op = ops[ k ];
30
+ if ( ! op ) continue;
31
+ const tag = list => list.map( value => ( { value, source: sources ? sources[ k ] : null } ) );
32
+ if ( op.explicit ) {
33
+
34
+ items = tag( op.explicit );
35
+ continue;
36
+
37
+ }
38
+
39
+ const drop = list => {
40
+
41
+ const keys = new Set( list.map( itemKey ) );
42
+ if ( keys.size ) items = items.filter( item => ! keys.has( itemKey( item.value ) ) );
43
+
44
+ };
45
+
46
+ drop( op.delete );
47
+ const present = new Set( items.map( item => itemKey( item.value ) ) );
48
+ for ( const item of tag( op.add ) ) if ( ! present.has( itemKey( item.value ) ) ) items.push( item );
49
+ drop( op.prepend );
50
+ items = [ ...tag( op.prepend ), ...items ];
51
+ drop( op.append );
52
+ items = [ ...items, ...tag( op.append ) ];
53
+
54
+ }
55
+
56
+ return items;
57
+
58
+ }
59
+
60
+ function assignOp( target, op, items ) {
61
+
62
+ if ( op === 'explicit' ) target.explicit = items;
63
+ else if ( op !== 'reorder' ) target[ op ].push( ...items );
64
+
65
+ }
66
+
67
+ export class PropSpec {
68
+
69
+ constructor( name ) {
70
+
71
+ this.name = name;
72
+ this.rel = false;
73
+ this.type = '';
74
+ this._value = undefined;
75
+ this._lazyValue = null;
76
+ this.hasValue = false;
77
+ this._timeSamples = null;
78
+ this._lazySamples = null;
79
+ this.targets = null;
80
+ this.connections = null;
81
+ this.meta = {};
82
+ this.uniform = false;
83
+ this.custom = false;
84
+
85
+ }
86
+
87
+ // A crate value is decoded the first time it is read: most of a production file is never asked for.
88
+ get value() {
89
+
90
+ if ( this._lazyValue ) {
91
+
92
+ this._value = this._lazyValue();
93
+ this._lazyValue = null;
94
+
95
+ }
96
+
97
+ return this._value;
98
+
99
+ }
100
+
101
+ set value( value ) {
102
+
103
+ this._value = value;
104
+ this._lazyValue = null;
105
+
106
+ }
107
+
108
+ get timeSamples() {
109
+
110
+ if ( this._lazySamples ) {
111
+
112
+ this._timeSamples = this._lazySamples();
113
+ this._lazySamples = null;
114
+
115
+ }
116
+
117
+ return this._timeSamples;
118
+
119
+ }
120
+
121
+ set timeSamples( samples ) {
122
+
123
+ this._timeSamples = samples;
124
+ this._lazySamples = null;
125
+
126
+ }
127
+
128
+ setTargets( op, paths ) {
129
+
130
+ assignOp( this.targets ??= listOp(), op, paths );
131
+
132
+ }
133
+
134
+ setConnections( op, paths ) {
135
+
136
+ assignOp( this.connections ??= listOp(), op, paths );
137
+
138
+ }
139
+
140
+ }
141
+
142
+ export class PrimSpec {
143
+
144
+ constructor( name ) {
145
+
146
+ this.name = name;
147
+ this.specifier = 'over';
148
+ this.typeName = '';
149
+ this.meta = {};
150
+ this.arcs = null;
151
+ this.variantSelection = null;
152
+ this.variantSets = null;
153
+ this.children = null;
154
+ this.props = null;
155
+ this.reorder = null;
156
+
157
+ }
158
+
159
+ child( name, create = false ) {
160
+
161
+ let spec = this.children?.get( name ) ?? null;
162
+ if ( ! spec && create ) {
163
+
164
+ this.children ??= new Map();
165
+ this.children.set( name, spec = new PrimSpec( name ) );
166
+
167
+ }
168
+
169
+ return spec;
170
+
171
+ }
172
+
173
+ variant( set, name, create = false ) {
174
+
175
+ let variants = this.variantSets?.get( set ) ?? null;
176
+ if ( ! variants ) {
177
+
178
+ if ( ! create ) return null;
179
+ this.variantSets ??= new Map();
180
+ this.variantSets.set( set, variants = new Map() );
181
+
182
+ }
183
+
184
+ let spec = variants.get( name ) ?? null;
185
+ if ( ! spec && create && name ) variants.set( name, spec = new PrimSpec( name ) );
186
+ return spec;
187
+
188
+ }
189
+
190
+ property( name, create = false ) {
191
+
192
+ let prop = this.props?.get( name ) ?? null;
193
+ if ( ! prop && create ) {
194
+
195
+ this.props ??= new Map();
196
+ this.props.set( name, prop = new PropSpec( name ) );
197
+
198
+ }
199
+
200
+ return prop;
201
+
202
+ }
203
+
204
+ setArc( key, op, items ) {
205
+
206
+ this.arcs ??= {};
207
+ assignOp( this.arcs[ key ] ??= listOp(), op, items );
208
+
209
+ }
210
+
211
+ }
212
+
213
+ export class Layer {
214
+
215
+ constructor( path ) {
216
+
217
+ this.path = path;
218
+ this.meta = {};
219
+ this.root = new PrimSpec( '' );
220
+ this.root.specifier = 'def';
221
+
222
+ }
223
+
224
+ }
225
+
226
+
227
+ // ── crate files ───────────────────────────────────────────────────
228
+
229
+ const T = {
230
+ Bool: 1, UChar: 2, Int: 3, UInt: 4, Int64: 5, UInt64: 6, Half: 7, Float: 8, Double: 9, String: 10, Token: 11,
231
+ AssetPath: 12, Matrix2d: 13, Matrix3d: 14, Matrix4d: 15, Quatd: 16, Quatf: 17, Quath: 18, Vec2d: 19, Vec2f: 20,
232
+ Vec2h: 21, Vec2i: 22, Vec3d: 23, Vec3f: 24, Vec3h: 25, Vec3i: 26, Vec4d: 27, Vec4f: 28, Vec4h: 29, Vec4i: 30,
233
+ Dictionary: 31, TokenListOp: 32, StringListOp: 33, PathListOp: 34, ReferenceListOp: 35, IntListOp: 36,
234
+ Int64ListOp: 37, UIntListOp: 38, UInt64ListOp: 39, PathVector: 40, TokenVector: 41, Specifier: 42, Permission: 43,
235
+ Variability: 44, VariantSelectionMap: 45, TimeSamples: 46, Payload: 47, DoubleVector: 48, LayerOffsetVector: 49,
236
+ StringVector: 50, ValueBlock: 51, Value: 52, PayloadListOp: 55, TimeCode: 56,
237
+ };
238
+
239
+ // Element layout of the fixed-size types: [ components, scalar kind ].
240
+ const LAYOUT = {
241
+ [ T.Bool ]: [ 1, 'bool' ], [ T.UChar ]: [ 1, 'u8' ], [ T.Int ]: [ 1, 'i32' ], [ T.UInt ]: [ 1, 'u32' ],
242
+ [ T.Int64 ]: [ 1, 'i64' ], [ T.UInt64 ]: [ 1, 'u64' ], [ T.Half ]: [ 1, 'f16' ], [ T.Float ]: [ 1, 'f32' ],
243
+ [ T.Double ]: [ 1, 'f64' ], [ T.TimeCode ]: [ 1, 'f64' ], [ T.Matrix2d ]: [ 4, 'f64' ], [ T.Matrix3d ]: [ 9, 'f64' ],
244
+ [ T.Matrix4d ]: [ 16, 'f64' ], [ T.Quatd ]: [ 4, 'f64' ], [ T.Quatf ]: [ 4, 'f32' ], [ T.Quath ]: [ 4, 'f16' ],
245
+ [ T.Vec2d ]: [ 2, 'f64' ], [ T.Vec2f ]: [ 2, 'f32' ], [ T.Vec2h ]: [ 2, 'f16' ], [ T.Vec2i ]: [ 2, 'i32' ],
246
+ [ T.Vec3d ]: [ 3, 'f64' ], [ T.Vec3f ]: [ 3, 'f32' ], [ T.Vec3h ]: [ 3, 'f16' ], [ T.Vec3i ]: [ 3, 'i32' ],
247
+ [ T.Vec4d ]: [ 4, 'f64' ], [ T.Vec4f ]: [ 4, 'f32' ], [ T.Vec4h ]: [ 4, 'f16' ], [ T.Vec4i ]: [ 4, 'i32' ],
248
+ };
249
+
250
+ const VECTOR_TYPES = new Set( [ T.Vec2d, T.Vec2f, T.Vec2i, T.Vec3d, T.Vec3f, T.Vec3h, T.Vec3i, T.Vec4d, T.Vec4f, T.Vec4h, T.Vec4i ] );
251
+ const MATRIX_SIZE = { [ T.Matrix2d ]: 2, [ T.Matrix3d ]: 3, [ T.Matrix4d ]: 4 };
252
+
253
+ let halfTable = null;
254
+ const bits = new DataView( new ArrayBuffer( 4 ) );
255
+
256
+ function halves() {
257
+
258
+ if ( halfTable ) return halfTable;
259
+ halfTable = new Float32Array( 65536 );
260
+ for ( let h = 0; h < 65536; h ++ ) {
261
+
262
+ const sign = h & 0x8000 ? - 1 : 1;
263
+ const exp = ( h >> 10 ) & 0x1F;
264
+ const frac = h & 0x3FF;
265
+ halfTable[ h ] = exp === 0 ? sign * 2 ** - 14 * ( frac / 1024 )
266
+ : exp === 31 ? ( frac ? NaN : sign * Infinity )
267
+ : sign * 2 ** ( exp - 15 ) * ( 1 + frac / 1024 );
268
+
269
+ }
270
+
271
+ return halfTable;
272
+
273
+ }
274
+
275
+ function lz4Block( src, start, end, out, at ) {
276
+
277
+ let i = start;
278
+ while ( i < end ) {
279
+
280
+ const token = src[ i ++ ];
281
+ let literals = token >> 4;
282
+ if ( literals === 15 ) {
283
+
284
+ let b;
285
+ do {
286
+
287
+ b = src[ i ++ ];
288
+ literals += b;
289
+
290
+ } while ( b === 255 );
291
+
292
+ }
293
+
294
+ out.set( src.subarray( i, i + literals ), at );
295
+ i += literals;
296
+ at += literals;
297
+ if ( i >= end ) break;
298
+
299
+ const offset = src[ i ] | ( src[ i + 1 ] << 8 );
300
+ i += 2;
301
+ let length = ( token & 15 ) + 4;
302
+ if ( length === 19 ) {
303
+
304
+ let b;
305
+ do {
306
+
307
+ b = src[ i ++ ];
308
+ length += b;
309
+
310
+ } while ( b === 255 );
311
+
312
+ }
313
+
314
+ let from = at - offset;
315
+ if ( offset >= length ) {
316
+
317
+ out.copyWithin( at, from, from + length );
318
+ at += length;
319
+
320
+ } else {
321
+
322
+ for ( let k = 0; k < length; k ++ ) out[ at ++ ] = out[ from ++ ];
323
+
324
+ }
325
+
326
+ }
327
+
328
+ return at;
329
+
330
+ }
331
+
332
+ /** TfFastCompression: a chunk count, then the one LZ4 block or, for large inputs, size-prefixed chunks. */
333
+ function decompress( src, maxSize ) {
334
+
335
+ const out = new Uint8Array( maxSize );
336
+ const chunks = src[ 0 ];
337
+ if ( chunks === 0 ) return out.subarray( 0, lz4Block( src, 1, src.length, out, 0 ) );
338
+ const view = new DataView( src.buffer, src.byteOffset, src.byteLength );
339
+ let i = 1, at = 0;
340
+ for ( let c = 0; c < chunks; c ++ ) {
341
+
342
+ const size = view.getInt32( i, true );
343
+ i += 4;
344
+ at = lz4Block( src, i, i + size, out, at );
345
+ i += size;
346
+
347
+ }
348
+
349
+ return out.subarray( 0, at );
350
+
351
+ }
352
+
353
+ /** USD's integer coding: a common delta, 2-bit codes, then the deltas that are not it. */
354
+ function decodeInts( data, n, wide ) {
355
+
356
+ const view = new DataView( data.buffer, data.byteOffset, data.byteLength );
357
+ const common = wide ? Number( view.getBigInt64( 0, true ) ) : view.getInt32( 0, true );
358
+ let codes = wide ? 8 : 4;
359
+ let at = codes + ( ( n * 2 + 7 ) >> 3 );
360
+ const out = wide ? new Float64Array( n ) : new Int32Array( n );
361
+ let value = 0;
362
+ for ( let i = 0; i < n; ) {
363
+
364
+ const byte = data[ codes ++ ];
365
+ for ( let j = 0; j < 4 && i < n; j ++, i ++ ) {
366
+
367
+ const code = ( byte >> ( j * 2 ) ) & 3;
368
+ let delta;
369
+ if ( code === 0 ) delta = common;
370
+ else if ( wide ) {
371
+
372
+ if ( code === 1 ) {
373
+
374
+ delta = view.getInt16( at, true );
375
+ at += 2;
376
+
377
+ } else if ( code === 2 ) {
378
+
379
+ delta = view.getInt32( at, true );
380
+ at += 4;
381
+
382
+ } else {
383
+
384
+ delta = Number( view.getBigInt64( at, true ) );
385
+ at += 8;
386
+
387
+ }
388
+
389
+ } else if ( code === 1 ) {
390
+
391
+ delta = view.getInt8( at );
392
+ at += 1;
393
+
394
+ } else if ( code === 2 ) {
395
+
396
+ delta = view.getInt16( at, true );
397
+ at += 2;
398
+
399
+ } else {
400
+
401
+ delta = view.getInt32( at, true );
402
+ at += 4;
403
+
404
+ }
405
+
406
+ value = wide ? value + delta : ( value + delta ) | 0;
407
+ out[ i ] = value;
408
+
409
+ }
410
+
411
+ }
412
+
413
+ return out;
414
+
415
+ }
416
+
417
+ /**
418
+ * A crate file, read the way OpenUSD's crateFile.cpp writes it (0.4.0 onwards): the section table, then the
419
+ * compressed token, field, field-set, path and spec tables; values are decoded on request.
420
+ */
421
+ export class Crate {
422
+
423
+ constructor( buffer ) {
424
+
425
+ this.buffer = buffer;
426
+ this.bytes = new Uint8Array( buffer );
427
+ this.view = new DataView( buffer );
428
+ this.pos = 0;
429
+ const magic = String.fromCharCode( ...this.bytes.subarray( 0, 8 ) );
430
+ if ( magic !== 'PXR-USDC' ) throw new Error( 'not a usdc layer' );
431
+ this.major = this.bytes[ 8 ];
432
+ this.minor = this.bytes[ 9 ];
433
+ this.patch = this.bytes[ 10 ];
434
+ if ( this.older( 0, 4 ) ) throw new Error( `usdc ${this.major}.${this.minor}.${this.patch} predates 0.4.0 and is not read` );
435
+
436
+ this.pos = 16;
437
+ this.pos = this.u64();
438
+ this.sections = {};
439
+ for ( let n = this.u64(); n > 0; n -- ) {
440
+
441
+ let name = '';
442
+ for ( let k = 0; k < 16; k ++ ) {
443
+
444
+ const c = this.bytes[ this.pos + k ];
445
+ if ( c === 0 ) break;
446
+ name += String.fromCharCode( c );
447
+
448
+ }
449
+
450
+ this.pos += 16;
451
+ this.sections[ name ] = { start: this.u64(), size: this.u64() };
452
+
453
+ }
454
+
455
+ this.readTokens();
456
+ this.readStrings();
457
+ this.readFields();
458
+ this.readFieldSets();
459
+ this.readPaths();
460
+ this.readSpecs();
461
+
462
+ }
463
+
464
+ older( major, minor ) {
465
+
466
+ return this.major < major || ( this.major === major && this.minor < minor );
467
+
468
+ }
469
+
470
+ seek( name ) {
471
+
472
+ const section = this.sections[ name ];
473
+ if ( ! section ) return false;
474
+ this.pos = section.start;
475
+ return true;
476
+
477
+ }
478
+
479
+ u8() {
480
+
481
+ return this.bytes[ this.pos ++ ];
482
+
483
+ }
484
+
485
+ i8() {
486
+
487
+ const v = this.view.getInt8( this.pos );
488
+ this.pos += 1;
489
+ return v;
490
+
491
+ }
492
+
493
+ u32() {
494
+
495
+ const v = this.view.getUint32( this.pos, true );
496
+ this.pos += 4;
497
+ return v;
498
+
499
+ }
500
+
501
+ i32() {
502
+
503
+ const v = this.view.getInt32( this.pos, true );
504
+ this.pos += 4;
505
+ return v;
506
+
507
+ }
508
+
509
+ u64() {
510
+
511
+ const lo = this.view.getUint32( this.pos, true );
512
+ const hi = this.view.getUint32( this.pos + 4, true );
513
+ this.pos += 8;
514
+ return hi * 0x100000000 + lo;
515
+
516
+ }
517
+
518
+ i64() {
519
+
520
+ const lo = this.view.getUint32( this.pos, true );
521
+ const hi = this.view.getInt32( this.pos + 4, true );
522
+ this.pos += 8;
523
+ return hi * 0x100000000 + lo;
524
+
525
+ }
526
+
527
+ f64() {
528
+
529
+ const v = this.view.getFloat64( this.pos, true );
530
+ this.pos += 8;
531
+ return v;
532
+
533
+ }
534
+
535
+ ints( n, wide = false ) {
536
+
537
+ const size = this.u64();
538
+ const src = this.bytes.subarray( this.pos, this.pos + size );
539
+ this.pos += size;
540
+ const encoded = ( wide ? 8 : 4 ) + ( ( n * 2 + 7 ) >> 3 ) + n * ( wide ? 8 : 4 );
541
+ return decodeInts( decompress( src, encoded ), n, wide );
542
+
543
+ }
544
+
545
+ readTokens() {
546
+
547
+ this.tokens = [];
548
+ if ( ! this.seek( 'TOKENS' ) ) return;
549
+ const n = this.u64();
550
+ const size = this.u64();
551
+ const compressed = this.u64();
552
+ const data = decompress( this.bytes.subarray( this.pos, this.pos + compressed ), size );
553
+ const decoder = new TextDecoder();
554
+ let start = 0;
555
+ for ( let i = 0; i < n; i ++ ) {
556
+
557
+ let end = start;
558
+ while ( end < data.length && data[ end ] !== 0 ) end ++;
559
+ this.tokens.push( decoder.decode( data.subarray( start, end ) ) );
560
+ start = end + 1;
561
+
562
+ }
563
+
564
+ }
565
+
566
+ readStrings() {
567
+
568
+ this.strings = [];
569
+ if ( ! this.seek( 'STRINGS' ) ) return;
570
+ for ( let n = this.u64(); n > 0; n -- ) this.strings.push( this.u32() );
571
+
572
+ }
573
+
574
+ readFields() {
575
+
576
+ if ( ! this.seek( 'FIELDS' ) ) return;
577
+ const n = this.u64();
578
+ this.fieldTokens = this.ints( n );
579
+ const size = this.u64();
580
+ const reps = decompress( this.bytes.subarray( this.pos, this.pos + size ), n * 8 );
581
+ this.fieldReps = new Uint32Array( reps.slice().buffer );
582
+
583
+ }
584
+
585
+ readFieldSets() {
586
+
587
+ this.fieldSets = new Int32Array( 0 );
588
+ if ( ! this.seek( 'FIELDSETS' ) ) return;
589
+ this.fieldSets = this.ints( this.u64() );
590
+
591
+ }
592
+
593
+ readPaths() {
594
+
595
+ if ( ! this.seek( 'PATHS' ) ) return;
596
+ const total = this.u64();
597
+ const n = this.u64();
598
+ const index = this.ints( n ), element = this.ints( n ), jumps = this.ints( n );
599
+ this.pathParent = new Int32Array( total ).fill( - 1 );
600
+ this.pathElement = new Array( total ).fill( '' );
601
+ this.pathIsProperty = new Uint8Array( total );
602
+
603
+ const pending = [[ 0, - 1 ]];
604
+ while ( pending.length ) {
605
+
606
+ let [ k, parent ] = pending.pop();
607
+ for ( ;; ) {
608
+
609
+ const here = index[ k ];
610
+ if ( parent >= 0 ) {
611
+
612
+ const token = element[ k ];
613
+ this.pathParent[ here ] = parent;
614
+ this.pathElement[ here ] = this.tokens[ Math.abs( token ) ] ?? '';
615
+ this.pathIsProperty[ here ] = token < 0 ? 1 : 0;
616
+
617
+ }
618
+
619
+ const jump = jumps[ k ];
620
+ const child = jump > 0 || jump === - 1, sibling = jump >= 0;
621
+ if ( child && sibling ) pending.push( [ k + jump, parent ] );
622
+ if ( child ) parent = here;
623
+ else if ( ! sibling ) break;
624
+ k ++;
625
+
626
+ }
627
+
628
+ }
629
+
630
+ this.pathStrings = new Array( total );
631
+
632
+ }
633
+
634
+ readSpecs() {
635
+
636
+ this.specPaths = this.specFieldSets = this.specTypes = new Int32Array( 0 );
637
+ if ( ! this.seek( 'SPECS' ) ) return;
638
+ const n = this.u64();
639
+ this.specPaths = this.ints( n );
640
+ this.specFieldSets = this.ints( n );
641
+ this.specTypes = this.ints( n );
642
+
643
+ }
644
+
645
+ /** A path index as USD writes it: `/a/b`, `/a/b{set=variant}`, `/a/b.prop`. */
646
+ path( i ) {
647
+
648
+ let s = this.pathStrings[ i ];
649
+ if ( s !== undefined ) return s;
650
+ const parent = this.pathParent[ i ];
651
+ const element = this.pathElement[ i ];
652
+ if ( parent < 0 ) s = '/';
653
+ else {
654
+
655
+ const base = this.path( parent );
656
+ s = this.pathIsProperty[ i ] ? `${base}.${element}`
657
+ : element.startsWith( '{' ) ? base + element
658
+ : base === '/' ? `/${element}` : `${base}/${element}`;
659
+
660
+ }
661
+
662
+ this.pathStrings[ i ] = s;
663
+ return s;
664
+
665
+ }
666
+
667
+ fieldsOf( set ) {
668
+
669
+ const out = [];
670
+ for ( let k = set; k < this.fieldSets.length; k ++ ) {
671
+
672
+ const f = this.fieldSets[ k ];
673
+ if ( f < 0 ) break;
674
+ out.push( [ this.tokens[ this.fieldTokens[ f ] ], this.fieldReps[ f * 2 ], this.fieldReps[ f * 2 + 1 ] ] );
675
+
676
+ }
677
+
678
+ return out;
679
+
680
+ }
681
+
682
+ value( lo, hi ) {
683
+
684
+ const type = ( hi >>> 16 ) & 0xFF;
685
+ const payload = lo + ( hi & 0xFFFF ) * 0x100000000;
686
+ if ( type === T.TimeSamples ) return this.timeSamples( payload );
687
+ if ( hi & 0x40000000 ) return this.inlined( type, lo );
688
+ const array = ( hi & 0x80000000 ) !== 0;
689
+ if ( array && payload === 0 ) return [];
690
+ const save = this.pos;
691
+ this.pos = payload;
692
+ const value = array ? this.array( type, ( hi & 0x20000000 ) !== 0 ) : this.scalar( type );
693
+ this.pos = save;
694
+ return value;
695
+
696
+ }
697
+
698
+ inlined( type, lo ) {
699
+
700
+ switch ( type ) {
701
+
702
+ case T.Bool: return lo !== 0;
703
+ case T.Int: return lo | 0;
704
+ case T.Float:
705
+ case T.Double:
706
+ case T.TimeCode: {
707
+
708
+ bits.setUint32( 0, lo, true );
709
+ return bits.getFloat32( 0, true );
710
+
711
+ }
712
+
713
+ case T.Half: return halves()[ lo & 0xFFFF ];
714
+ case T.Token:
715
+ case T.AssetPath: return this.tokens[ lo ] ?? '';
716
+ case T.String: return this.tokens[ this.strings[ lo ] ] ?? '';
717
+ case T.Vec2h: return [ halves()[ lo & 0xFFFF ], halves()[ lo >>> 16 ] ];
718
+ case T.ValueBlock: return null;
719
+ case T.Dictionary: return {};
720
+
721
+ }
722
+
723
+ const signed = k => ( ( lo >>> ( k * 8 ) ) << 24 ) >> 24;
724
+ if ( VECTOR_TYPES.has( type ) ) return Array.from( { length: LAYOUT[ type ][ 0 ] }, ( _, k ) => signed( k ) );
725
+ const size = MATRIX_SIZE[ type ];
726
+ if ( size ) {
727
+
728
+ const m = new Array( size * size ).fill( 0 );
729
+ for ( let k = 0; k < size; k ++ ) m[ k * size + k ] = signed( k );
730
+ return m;
731
+
732
+ }
733
+
734
+ return lo;
735
+
736
+ }
737
+
738
+ element( kind ) {
739
+
740
+ switch ( kind ) {
741
+
742
+ case 'bool': return this.u8() !== 0;
743
+ case 'u8': return this.u8();
744
+ case 'i32': return this.i32();
745
+ case 'u32': return this.u32();
746
+ case 'i64': return this.i64();
747
+ case 'u64': return this.u64();
748
+ case 'f16': {
749
+
750
+ const v = halves()[ this.view.getUint16( this.pos, true ) ];
751
+ this.pos += 2;
752
+ return v;
753
+
754
+ }
755
+
756
+ case 'f32': {
757
+
758
+ const v = this.view.getFloat32( this.pos, true );
759
+ this.pos += 4;
760
+ return v;
761
+
762
+ }
763
+
764
+ default: return this.f64();
765
+
766
+ }
767
+
768
+ }
769
+
770
+ listOp( read ) {
771
+
772
+ const bits = this.u8();
773
+ const op = listOp();
774
+ const list = () => {
775
+
776
+ const out = [];
777
+ for ( let n = this.u64(); n > 0; n -- ) out.push( read() );
778
+ return out;
779
+
780
+ };
781
+
782
+ if ( bits & 1 ) op.explicit = [];
783
+ if ( bits & 2 ) op.explicit = list();
784
+ if ( bits & 4 ) op.add = list();
785
+ if ( bits & 32 ) op.prepend = list();
786
+ if ( bits & 64 ) op.append = list();
787
+ if ( bits & 8 ) op.delete = list();
788
+ if ( bits & 16 ) list();
789
+ return op;
790
+
791
+ }
792
+
793
+ string() {
794
+
795
+ return this.tokens[ this.strings[ this.u32() ] ] ?? '';
796
+
797
+ }
798
+
799
+ reference() {
800
+
801
+ const asset = this.string();
802
+ const path = this.path( this.u32() );
803
+ this.f64();
804
+ this.f64();
805
+ this.dictionary();
806
+ return new Ref( asset, path === '/' ? '' : path );
807
+
808
+ }
809
+
810
+ payload() {
811
+
812
+ const asset = this.string();
813
+ const path = this.path( this.u32() );
814
+ if ( ! this.older( 0, 8 ) ) {
815
+
816
+ this.f64();
817
+ this.f64();
818
+
819
+ }
820
+
821
+ return new Ref( asset, path === '/' ? '' : path );
822
+
823
+ }
824
+
825
+ /** A value inside another (a dictionary's): an offset past whatever it nested, then its rep, then what follows. */
826
+ recursive() {
827
+
828
+ const start = this.pos;
829
+ this.pos = start + this.i64();
830
+ return this.value( this.u32(), this.u32() );
831
+
832
+ }
833
+
834
+ dictionary() {
835
+
836
+ const out = {};
837
+ for ( let n = this.u64(); n > 0; n -- ) {
838
+
839
+ const key = this.string();
840
+ out[ key ] = this.recursive();
841
+
842
+ }
843
+
844
+ return out;
845
+
846
+ }
847
+
848
+ scalar( type ) {
849
+
850
+ const layout = LAYOUT[ type ];
851
+ if ( layout ) {
852
+
853
+ if ( layout[ 0 ] === 1 ) return this.element( layout[ 1 ] );
854
+ return Array.from( { length: layout[ 0 ] }, () => this.element( layout[ 1 ] ) );
855
+
856
+ }
857
+
858
+ switch ( type ) {
859
+
860
+ case T.String: return this.string();
861
+ case T.Token:
862
+ case T.AssetPath: return this.tokens[ this.u32() ] ?? '';
863
+ case T.Specifier:
864
+ case T.Permission:
865
+ case T.Variability: return this.u32();
866
+ case T.Dictionary: return this.dictionary();
867
+ case T.TokenListOp: return this.listOp( () => this.tokens[ this.u32() ] ?? '' );
868
+ case T.StringListOp: return this.listOp( () => this.string() );
869
+ case T.PathListOp: return this.listOp( () => this.path( this.u32() ) );
870
+ case T.ReferenceListOp: return this.listOp( () => this.reference() );
871
+ case T.PayloadListOp: return this.listOp( () => this.payload() );
872
+ case T.IntListOp: return this.listOp( () => this.i32() );
873
+ case T.UIntListOp: return this.listOp( () => this.u32() );
874
+ case T.Int64ListOp: return this.listOp( () => this.i64() );
875
+ case T.UInt64ListOp: return this.listOp( () => this.u64() );
876
+ case T.Payload: return this.payload();
877
+ case T.PathVector: return Array.from( { length: this.u64() }, () => this.path( this.u32() ) );
878
+ case T.TokenVector: return Array.from( { length: this.u64() }, () => this.tokens[ this.u32() ] ?? '' );
879
+ case T.StringVector: return Array.from( { length: this.u64() }, () => this.string() );
880
+ case T.DoubleVector: return Float64Array.from( { length: this.u64() }, () => this.f64() );
881
+ case T.LayerOffsetVector: return Array.from( { length: this.u64() }, () => [ this.f64(), this.f64() ] );
882
+ case T.VariantSelectionMap: {
883
+
884
+ const out = {};
885
+ for ( let n = this.u64(); n > 0; n -- ) {
886
+
887
+ const key = this.string();
888
+ out[ key ] = this.string();
889
+
890
+ }
891
+
892
+ return out;
893
+
894
+ }
895
+
896
+ case T.Value: return this.recursive();
897
+ default: return null;
898
+
899
+ }
900
+
901
+ }
902
+
903
+ typed( Type, count ) {
904
+
905
+ const bytes = count * Type.BYTES_PER_ELEMENT;
906
+ const out = new Type( this.buffer.slice( this.pos, this.pos + bytes ) );
907
+ this.pos += bytes;
908
+ return out;
909
+
910
+ }
911
+
912
+ array( type, compressed ) {
913
+
914
+ if ( this.older( 0, 5 ) ) this.u32();
915
+ const n = this.older( 0, 7 ) ? this.u32() : this.u64();
916
+ if ( compressed ) return this.compressedArray( type, n );
917
+
918
+ const layout = LAYOUT[ type ];
919
+ if ( layout ) {
920
+
921
+ const [ components, kind ] = layout;
922
+ const count = n * components;
923
+ switch ( kind ) {
924
+
925
+ case 'f32': return this.typed( Float32Array, count );
926
+ case 'f64': return this.typed( Float64Array, count );
927
+ case 'i32': return this.typed( Int32Array, count );
928
+ case 'u32': return this.typed( Uint32Array, count );
929
+ case 'u8': return this.typed( Uint8Array, count );
930
+ case 'f16': {
931
+
932
+ const raw = this.typed( Uint16Array, count );
933
+ const table = halves();
934
+ const out = new Float32Array( count );
935
+ for ( let i = 0; i < count; i ++ ) out[ i ] = table[ raw[ i ] ];
936
+ return out;
937
+
938
+ }
939
+
940
+ default: return Array.from( { length: count }, () => this.element( kind ) );
941
+
942
+ }
943
+
944
+ }
945
+
946
+ switch ( type ) {
947
+
948
+ case T.String: return Array.from( { length: n }, () => this.string() );
949
+ case T.Token:
950
+ case T.AssetPath: return Array.from( { length: n }, () => this.tokens[ this.u32() ] ?? '' );
951
+ default: return null;
952
+
953
+ }
954
+
955
+ }
956
+
957
+ compressedArray( type, n ) {
958
+
959
+ switch ( type ) {
960
+
961
+ case T.Int: return this.ints( n );
962
+ case T.UInt: return new Uint32Array( this.ints( n ).buffer );
963
+ case T.Int64:
964
+ case T.UInt64: return this.ints( n, true );
965
+ case T.Half:
966
+ case T.Float:
967
+ case T.Double: {
968
+
969
+ const Out = type === T.Double ? Float64Array : Float32Array;
970
+ const code = this.i8();
971
+ if ( code === 0x69 ) return Out.from( this.ints( n ) );
972
+ if ( code !== 0x74 ) throw new Error( `usdc: unknown float array coding ${code}` );
973
+ const lut = Array.from( { length: this.u32() }, () => this.element( type === T.Half ? 'f16' : type === T.Float ? 'f32' : 'f64' ) );
974
+ const indices = this.ints( n );
975
+ const out = new Out( n );
976
+ for ( let i = 0; i < n; i ++ ) out[ i ] = lut[ indices[ i ] ];
977
+ return out;
978
+
979
+ }
980
+
981
+ default: throw new Error( `usdc: compressed array of type ${type} is not read` );
982
+
983
+ }
984
+
985
+ }
986
+
987
+ // The times' value rep sits behind one relative offset; the value reps follow another just after it.
988
+ timeSamples( payload ) {
989
+
990
+ const save = this.pos;
991
+ this.pos = payload;
992
+ this.pos = payload + this.i64();
993
+ const times = [ this.u32(), this.u32() ];
994
+ const start = this.pos;
995
+ this.pos = start + this.i64();
996
+ const reps = [];
997
+ for ( let n = this.u64(); n > 0; n -- ) reps.push( [ this.u32(), this.u32() ] );
998
+ this.pos = save;
999
+ const values = reps.map( ( [ lo, hi ] ) => this.value( lo, hi ) );
1000
+ return new Map( Array.from( this.value( ...times ) ?? [], ( t, i ) => [ t, values[ i ] ] ) );
1001
+
1002
+ }
1003
+
1004
+ }
1005
+
1006
+ const PRIM = 6, PSEUDO_ROOT = 7, VARIANT = 10, ATTRIBUTE = 1, RELATIONSHIP = 8;
1007
+ const SPECIFIER = [ 'def', 'over', 'class' ];
1008
+
1009
+ function applyPrimField( spec, key, value ) {
1010
+
1011
+ switch ( key ) {
1012
+
1013
+ case 'specifier': spec.specifier = SPECIFIER[ value ] ?? 'over'; break;
1014
+ case 'typeName': spec.typeName = value || ''; break;
1015
+ case 'primChildren':
1016
+ case 'properties':
1017
+ case 'variantChildren':
1018
+ case 'variantSetChildren':
1019
+ break;
1020
+ case 'references':
1021
+ case 'specializes':
1022
+ case 'apiSchemas':
1023
+ case 'variantSetNames':
1024
+ if ( value ) ( spec.arcs ??= {} )[ key ] = value;
1025
+ break;
1026
+ case 'inheritPaths':
1027
+ if ( value ) ( spec.arcs ??= {} ).inherits = value;
1028
+ break;
1029
+ case 'payload':
1030
+ if ( value instanceof Ref ) ( spec.arcs ??= {} ).payload = { ...listOp(), explicit: [ value ] };
1031
+ else if ( value ) ( spec.arcs ??= {} ).payload = value;
1032
+ break;
1033
+ case 'variantSelection':
1034
+ if ( value ) spec.variantSelection = value;
1035
+ break;
1036
+ default:
1037
+ spec.meta[ key ] = value;
1038
+
1039
+ }
1040
+
1041
+ }
1042
+
1043
+ /** The buffer stays held by the layer's undecoded values. */
1044
+ export function parseUSDC( buffer, path = '' ) {
1045
+
1046
+ const crate = new Crate( buffer );
1047
+ const layer = new Layer( path );
1048
+ const specs = new Map();
1049
+
1050
+ const primSpec = i => {
1051
+
1052
+ let spec = specs.get( i );
1053
+ if ( spec ) return spec;
1054
+ const parent = crate.pathParent[ i ];
1055
+ if ( parent < 0 ) spec = layer.root;
1056
+ else {
1057
+
1058
+ const owner = primSpec( parent );
1059
+ const element = crate.pathElement[ i ];
1060
+ if ( element.startsWith( '{' ) ) {
1061
+
1062
+ const [ set, name ] = element.slice( 1, - 1 ).split( '=' );
1063
+ spec = owner.variant( set, name, true ) ?? owner;
1064
+
1065
+ } else {
1066
+
1067
+ spec = owner.child( element, true );
1068
+
1069
+ }
1070
+
1071
+ }
1072
+
1073
+ specs.set( i, spec );
1074
+ return spec;
1075
+
1076
+ };
1077
+
1078
+ const ordered = [];
1079
+ for ( let s = 0; s < crate.specTypes.length; s ++ ) {
1080
+
1081
+ const type = crate.specTypes[ s ];
1082
+ const index = crate.specPaths[ s ];
1083
+ const fields = crate.fieldsOf( crate.specFieldSets[ s ] );
1084
+
1085
+ if ( type === PSEUDO_ROOT ) {
1086
+
1087
+ for ( const [ key, lo, hi ] of fields ) if ( key !== 'primChildren' ) layer.meta[ key ] = crate.value( lo, hi );
1088
+ continue;
1089
+
1090
+ }
1091
+
1092
+ if ( type === PRIM || type === VARIANT ) {
1093
+
1094
+ const spec = primSpec( index );
1095
+ for ( const [ key, lo, hi ] of fields ) {
1096
+
1097
+ const value = crate.value( lo, hi );
1098
+ if ( key === 'primChildren' && value?.length ) ordered.push( [ spec, value ] );
1099
+ applyPrimField( spec, key, value );
1100
+
1101
+ }
1102
+
1103
+ continue;
1104
+
1105
+ }
1106
+
1107
+ if ( ( type !== ATTRIBUTE && type !== RELATIONSHIP ) || ! crate.pathIsProperty[ index ] ) continue;
1108
+ const prop = primSpec( crate.pathParent[ index ] ).property( crate.pathElement[ index ], true );
1109
+ prop.rel = type === RELATIONSHIP;
1110
+ for ( const [ key, lo, hi ] of fields ) {
1111
+
1112
+ if ( key === 'default' ) {
1113
+
1114
+ prop.hasValue = true;
1115
+ prop._lazyValue = () => crate.value( lo, hi );
1116
+
1117
+ } else if ( key === 'timeSamples' ) {
1118
+
1119
+ prop._lazySamples = () => crate.value( lo, hi );
1120
+
1121
+ } else {
1122
+
1123
+ const value = crate.value( lo, hi );
1124
+ if ( key === 'typeName' ) prop.type = value;
1125
+ else if ( key === 'targetPaths' ) prop.targets = value;
1126
+ else if ( key === 'connectionPaths' ) prop.connections = value;
1127
+ else if ( key === 'variability' ) prop.uniform = value === 1;
1128
+ else if ( key === 'custom' ) prop.custom = value === true;
1129
+ else prop.meta[ key ] = value;
1130
+
1131
+ }
1132
+
1133
+ }
1134
+
1135
+ }
1136
+
1137
+ for ( const [ spec, names ] of ordered ) {
1138
+
1139
+ if ( ! spec.children ) continue;
1140
+ const children = new Map();
1141
+ for ( const name of names ) if ( spec.children.has( name ) ) children.set( name, spec.children.get( name ) );
1142
+ for ( const [ name, child ] of spec.children ) if ( ! children.has( name ) ) children.set( name, child );
1143
+ spec.children = children;
1144
+
1145
+ }
1146
+
1147
+ return layer;
1148
+
1149
+ }