rayzee 11.1.0 → 11.2.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 (34) hide show
  1. package/README.md +29 -7
  2. package/dist/{ArchiveImporter-Hn35o6Z5.js → ArchiveImporter-eNlu0_6F.js} +882 -829
  3. package/dist/{BidirectionalIntegrator-CBw8hkeu.js → BidirectionalIntegrator-D1-6UySB.js} +226 -226
  4. package/dist/{NeuralRetouch-BzNpiVHZ.js → NeuralRetouch-DFGbnmLb.js} +2 -2
  5. package/dist/{NeuralSuperRes-Bk7bHg2B.js → NeuralSuperRes-BtXvyJQl.js} +2 -2
  6. package/dist/{PathTracer-72XufKAr.js → PathTracer-BHXGJtPN.js} +2959 -3001
  7. package/dist/{PhysicalSky-BgjdV88k.js → PhysicalSky-DN6u8UX4.js} +1 -1
  8. package/dist/{RayzeeRenderer-1QRO97eq.js → RayzeeRenderer-Dw1x8mVL.js} +401 -362
  9. package/dist/SceneMetadata-D2Sh-0e-.js +110 -0
  10. package/dist/addons/archives.es.js +1 -1
  11. package/dist/addons/bidirectional.es.js +1 -1
  12. package/dist/addons/physical-sky.es.js +1 -1
  13. package/dist/addons/storage.es.js +1 -1
  14. package/dist/{identity-DrQsGT2o.js → identity-C1cLD1C0.js} +14 -4
  15. package/dist/{openStorage-DwcBRUj7.js → openStorage-Fe9BoS1_.js} +1 -1
  16. package/dist/rayzee-core.es.js +6 -6
  17. package/dist/rayzee.es.js +828 -828
  18. package/dist/rayzee.umd.js +95 -94
  19. package/dist/{sceneCachePolicy-C67jbci-.js → sceneCachePolicy-DA7iGoL4.js} +71 -29
  20. package/package.json +1 -1
  21. package/src/EngineDefaults.js +1 -1
  22. package/src/PathTracerApp.js +1 -0
  23. package/src/Processor/ArchiveImporter.js +130 -96
  24. package/src/Processor/ArchiveReader.js +46 -3
  25. package/src/Processor/AssetLoader.js +26 -1
  26. package/src/Processor/archiveFormats.js +35 -0
  27. package/src/RayzeeRenderer.js +43 -12
  28. package/src/Storage/identity.js +22 -1
  29. package/src/Storage/index.js +1 -1
  30. package/src/TSL/MaterialEvaluation.js +4 -3
  31. package/src/core.js +1 -1
  32. package/src/index.js +2 -2
  33. package/dist/archiveFormats-tnAoUL1j.js +0 -94
  34. /package/dist/{ToneMapGPU-CjU3osDd.js → ToneMapGPU-BOjpul7A.js} +0 -0
@@ -546,8 +546,8 @@ export function createTarIndexer( { filter = null, sink = null } = {} ) {
546
546
  * @param {object} [options] - `filter` and `retain` as in readTar
547
547
  * @param {{listing: Array}} [options.index] - a saved index (`result.index`): skips the walk
548
548
  * @param {boolean} [options.headersOnly] - index by seeking between headers; nothing is retained
549
- * @returns {Promise<{entries, listing, read: (path:string)=>Promise<Uint8Array|null>, truncated,
550
- * index: ?{v:number, listing:Array}}>}
549
+ * @returns {Promise<{entries, listing, read: (path:string)=>Promise<Uint8Array|null>,
550
+ * slice: (path:string)=>Promise<Blob|null>, truncated, index: ?{v:number, listing:Array}}>}
551
551
  */
552
552
  export async function openTar( source, options = {} ) {
553
553
 
@@ -594,7 +594,50 @@ export async function openTar( source, options = {} ) {
594
594
 
595
595
  };
596
596
 
597
- return { entries, listing, read, readHead, retainedBytes, truncated, indexed: byPath.size, index: full ? { v: 1, listing: full } : null };
597
+ const slice = async ( path ) => {
598
+
599
+ if ( entries[ path ] ) return new Blob( [ entries[ path ] ] );
600
+ const e = byPath.get( path );
601
+ return e ? source.slice( e.offset, e.offset + e.size ) : null;
602
+
603
+ };
604
+
605
+ return { entries, listing, read, readHead, slice, retainedBytes, truncated, indexed: byPath.size, index: full ? { v: 1, listing: full } : null };
606
+
607
+ }
608
+
609
+ /**
610
+ * A folder on disk with the shape of `openTar` and `openZip`: every file is listed, and read only when asked for.
611
+ * @param {{files: Array<{path: string, file: Blob}>}} folder - from `localFolder`
612
+ * @param {{filter?: (path:string, size:number) => boolean}} [options]
613
+ */
614
+ export function openFolder( folder, { filter = null } = {} ) {
615
+
616
+ const byPath = new Map();
617
+ const listing = folder.files.map( ( { path, file } ) => {
618
+
619
+ if ( filter && ! filter( path, file.size ) ) return { path, size: file.size };
620
+ byPath.set( path, file );
621
+ return { path, size: file.size, offset: 0 };
622
+
623
+ } );
624
+
625
+ const slice = async ( path ) => byPath.get( path ) ?? null;
626
+ const read = async ( path ) => {
627
+
628
+ const file = byPath.get( path );
629
+ return file ? new Uint8Array( await file.arrayBuffer() ) : null;
630
+
631
+ };
632
+
633
+ const readHead = async ( path, bytes ) => {
634
+
635
+ const file = byPath.get( path );
636
+ return file ? new Uint8Array( await file.slice( 0, bytes ).arrayBuffer() ) : null;
637
+
638
+ };
639
+
640
+ return { entries: Object.create( null ), listing, read, readHead, slice, retainedBytes: 0, truncated: false, indexed: byPath.size };
598
641
 
599
642
  }
600
643
 
@@ -441,7 +441,32 @@ export class AssetLoader extends EventDispatcher {
441
441
 
442
442
  } catch ( error ) {
443
443
 
444
- this.dispatchEvent( { type: 'error', message: error.message, filename } );
444
+ if ( error?.code !== 'ARCHIVE_NEEDS_ELEMENT' ) this.dispatchEvent( { type: 'error', message: error.message, filename } );
445
+ throw error;
446
+
447
+ }
448
+
449
+ }
450
+
451
+ /**
452
+ * Loads a folder's files as one model — read by the archive importer, as the same folder zipped would be.
453
+ * @param {{name: string, files: Array<{path: string, file: Blob}>}} folder - from `localFolder`
454
+ * @param {object} [options] - as loadAssetFromFile
455
+ */
456
+ async loadFolder( folder, options = {} ) {
457
+
458
+ const archives = await this._archiveImporter();
459
+ if ( ! archives ) throw new Error( `${folder.name}: folders are read by ${ARCHIVES.addOn} — install it with ${ARCHIVES.install}` );
460
+
461
+ updateLoading( { isLoading: true, status: `Loading ${folder.name}...`, progress: 2 } );
462
+ try {
463
+
464
+ return await archives.loadFolder( folder, options );
465
+
466
+ } catch ( error ) {
467
+
468
+ if ( error?.code === 'ARCHIVE_NEEDS_ELEMENT' ) error.file = folder;
469
+ else this.dispatchEvent( { type: 'error', message: error.message, filename: folder.name } );
445
470
  throw error;
446
471
 
447
472
  }
@@ -5,3 +5,38 @@ export const ARCHIVE_FORMATS = Object.freeze( {
5
5
  'tgz': { type: 'archive', name: 'Gzipped TAR Archive' },
6
6
  'tar': { type: 'archive', name: 'TAR Archive' },
7
7
  } );
8
+
9
+ const isBlob = value => typeof Blob !== 'undefined' && value instanceof Blob;
10
+
11
+ /** Whether `loadFile` was handed a folder (`{ files }`) rather than a File or a URL. */
12
+ export const isFolderInput = input => !! input && typeof input === 'object' && ! isBlob( input ) && input.files != null;
13
+
14
+ const hidden = segment => segment.startsWith( '.' ) || segment === '__MACOSX';
15
+
16
+ /**
17
+ * A folder's files as `{ name, files: [{ path, file }] }`: paths '/'-separated and sorted, hidden files and folders
18
+ * left out. Each of `files` is a File, whose path is its `webkitRelativePath` (a folder picker sets it) or else its
19
+ * name, or `{ path, file }`. `name` defaults to the folder all paths share, else the first file `isModel` accepts.
20
+ * @param {{name?: string, files: Iterable<File|{path: string, file: Blob}>}} input
21
+ * @param {{isModel?: function(string): boolean}} [options]
22
+ */
23
+ export function localFolder( { name = null, files }, { isModel = () => false } = {} ) {
24
+
25
+ const byPath = new Map();
26
+ for ( const item of files ) {
27
+
28
+ const file = isBlob( item ) ? item : item.file;
29
+ const raw = isBlob( item ) ? ( item.webkitRelativePath || item.name ) : item.path;
30
+ const path = String( raw ?? '' ).replace( /\\/g, '/' ).split( '/' ).filter( s => s && s !== '.' ).join( '/' );
31
+ if ( ! path || ! file || path.split( '/' ).some( hidden ) ) continue;
32
+ byPath.set( path, { path, file } );
33
+
34
+ }
35
+
36
+ const list = [ ...byPath.values() ].sort( ( a, b ) => ( a.path < b.path ? - 1 : a.path > b.path ? 1 : 0 ) );
37
+ const top = list[ 0 ]?.path.split( '/' )[ 0 ];
38
+ const shared = list.length > 0 && list.every( e => e.path.startsWith( top + '/' ) ) ? top : null;
39
+ const named = name ?? shared ?? ( list.find( e => isModel( e.path ) ) ?? list[ 0 ] )?.path.split( '/' ).pop() ?? 'Folder';
40
+ return { name: named, files: list, flat: shared === null && list.every( e => ! e.path.includes( '/' ) ) };
41
+
42
+ }
@@ -20,7 +20,8 @@ import { EngineEvents, LEGACY_EVENT_NAMES } from './EngineEvents.js';
20
20
  import { IssueLog, ISSUE_CODES, EngineIssueError } from './EngineIssues.js';
21
21
  import { getAssetConfig, isAssetConfigured } from './AssetConfig.js';
22
22
  import { nameFromUrl } from './Storage/DownloadCache.js';
23
- import { fileIdentity, identityKey } from './Storage/identity.js';
23
+ import { fileIdentity, folderIdentity, identityKey } from './Storage/identity.js';
24
+ import { isFolderInput, localFolder } from './Processor/archiveFormats.js';
24
25
  import { SETTING_SOURCE } from './RenderSettings.js';
25
26
  import { toneMapToRGBA8 } from './Processor/ToneMapCPU.js';
26
27
  import { PackedToneMapper } from './Processor/ToneMapGPU.js';
@@ -209,7 +210,7 @@ export class RayzeeRenderer extends EventDispatcher {
209
210
  if ( options.profile !== undefined ) {
210
211
 
211
212
  throw new Error( 'the `profile` option was removed: the engine has one set of defaults. For the old \'physical\' '
212
- + 'profile set `areaLightIntensityScale: 1` and `dofMode: \'physical\'` through `settings`.' );
213
+ + 'profile set `dofMode: \'physical\'` through `settings`.' );
213
214
 
214
215
  }
215
216
 
@@ -714,7 +715,7 @@ export class RayzeeRenderer extends EventDispatcher {
714
715
  this._storageRelease?.();
715
716
  this._storageRelease = null;
716
717
  this.storage = null;
717
- this._sceneSource = this._sceneSourceFile = null;
718
+ this._sceneSource = this._sceneSourceInput = null;
718
719
 
719
720
  this._issues.detach(); // onIssue captures `this`; see IssueLog.detach()
720
721
 
@@ -841,7 +842,7 @@ export class RayzeeRenderer extends EventDispatcher {
841
842
  this._releaseSceneState();
842
843
 
843
844
  this.assetLoader?.releaseTargetModel();
844
- this._sceneSource = this._sceneSourceFile = null;
845
+ this._sceneSource = this._sceneSourceInput = null;
845
846
 
846
847
  // Clear lights in the WebGPU light scene
847
848
  this.lightManager?.clearLights?.();
@@ -963,7 +964,7 @@ export class RayzeeRenderer extends EventDispatcher {
963
964
 
964
965
  /**
965
966
  * Loads a user-supplied File (drag-drop, file picker) — model, archive, or environment
966
- * map, dispatched by extension.
967
+ * map, dispatched by extension — or a folder of files, read as the same folder zipped would be.
967
968
  *
968
969
  * Prefer this over driving `assetLoader.loadAssetFromFile()` directly. That bypasses the
969
970
  * in-progress guard, and AssetLoader disposes the outgoing model before it knows whether
@@ -972,7 +973,9 @@ export class RayzeeRenderer extends EventDispatcher {
972
973
  * tracer rendering buffers whose geometry has been freed. Here a concurrent call throws
973
974
  * LOAD_IN_PROGRESS before anything is touched.
974
975
  *
975
- * @param {File|string} file - a File, or a URL to download (through the download cache)
976
+ * @param {File|string|{name?: string, files: Iterable<File|{path: string, file: Blob}>}} file - a File, a URL to
977
+ * download (through the download cache), or a folder: `{ files }` — a folder picker's FileList, whose files carry
978
+ * their `webkitRelativePath`, or `{ path, file }` pairs; `name` defaults to the folder they share
976
979
  * @param {object} [options] - forwarded to the archive loader: `element` to load one
977
980
  * subtree of a multi-part scene, `pbrtEntry` to choose among several .pbrt scenes. For a
978
981
  * URL also `filename` and `cacheKey` (see AssetLoader.loadAssetFromUrl).
@@ -998,6 +1001,25 @@ export class RayzeeRenderer extends EventDispatcher {
998
1001
 
999
1002
  }
1000
1003
 
1004
+ if ( isFolderInput( file ) ) {
1005
+
1006
+ const folder = localFolder( file, { isModel: path => this.assetLoader?.getFileFormat( path )?.type === 'model' } );
1007
+ if ( folder.files.length === 0 ) throw new Error( `${folder.name} holds no files to load` );
1008
+ await this._loadWithSceneRebuild(
1009
+ () => this.assetLoader.loadFolder( folder, options ),
1010
+ { type: EngineEvents.MODEL_LOADED, filename: folder.name },
1011
+ async () => {
1012
+
1013
+ const id = await folderIdentity( folder );
1014
+ return { kind: 'local-folder', folder: id, key: identityKey( id ), ...( folder.flat ? { flat: true } : {} ), ...partOf( options ) };
1015
+
1016
+ }
1017
+ );
1018
+ this._sceneSourceInput = folder;
1019
+ return;
1020
+
1021
+ }
1022
+
1001
1023
  const format = this.assetLoader?.getFileFormat( file?.name || '' );
1002
1024
  if ( ! format ) throw this.assetLoader.formatError( file?.name || '' );
1003
1025
 
@@ -1014,7 +1036,7 @@ export class RayzeeRenderer extends EventDispatcher {
1014
1036
 
1015
1037
  }
1016
1038
  );
1017
- this._sceneSourceFile = file;
1039
+ this._sceneSourceInput = file;
1018
1040
  return;
1019
1041
 
1020
1042
  }
@@ -1121,8 +1143,10 @@ export class RayzeeRenderer extends EventDispatcher {
1121
1143
  /**
1122
1144
  * Where the model on screen came from, as plain data — what a saved session reopens:
1123
1145
  * `{ kind: 'url', url, cacheKey, filename?, element?, pbrtEntry? }`,
1124
- * `{ kind: 'local-file', file: {name, size, lastModified, sample}, key, element?, pbrtEntry? }` or
1125
- * `{ kind: 'object3d', name }`. Null before a load and after {@link unloadScene}.
1146
+ * `{ kind: 'local-file', file: {name, size, lastModified, sample}, key, element?, pbrtEntry? }`,
1147
+ * `{ kind: 'local-folder', folder: {name, size, lastModified, sample, files}, key, flat?, element?, pbrtEntry? }`
1148
+ * (`flat` when it was loose files rather than one folder) or `{ kind: 'object3d', name }`. Null before a load and
1149
+ * after {@link unloadScene}.
1126
1150
  * @returns {?Object}
1127
1151
  */
1128
1152
  get sceneSource() {
@@ -1134,7 +1158,14 @@ export class RayzeeRenderer extends EventDispatcher {
1134
1158
  /** The File a local load came from, so a host can save a project that carries it; null otherwise. */
1135
1159
  get sceneSourceFile() {
1136
1160
 
1137
- return this._sceneSourceFile ?? null;
1161
+ return this._sceneSourceInput && ! isFolderInput( this._sceneSourceInput ) ? this._sceneSourceInput : null;
1162
+
1163
+ }
1164
+
1165
+ /** The folder a local load came from, as `{ name, files: [{ path, file }] }`; null otherwise. */
1166
+ get sceneSourceFolder() {
1167
+
1168
+ return isFolderInput( this._sceneSourceInput ) ? this._sceneSourceInput : null;
1138
1169
 
1139
1170
  }
1140
1171
 
@@ -1149,7 +1180,7 @@ export class RayzeeRenderer extends EventDispatcher {
1149
1180
 
1150
1181
  await loadFn();
1151
1182
  this._sceneSource = typeof source === 'function' ? await source() : source;
1152
- this._sceneSourceFile = null;
1183
+ this._sceneSourceInput = null;
1153
1184
  // A fresh model re-establishes the emissive-sampling auto-default (incremental
1154
1185
  // rebuilds — add/remove object, texture reprocess — preserve the user's choice).
1155
1186
  this._emissiveSamplingUserSet = false;
@@ -1196,7 +1227,7 @@ export class RayzeeRenderer extends EventDispatcher {
1196
1227
  */
1197
1228
  _discardFailedLoad() {
1198
1229
 
1199
- this._sceneSource = this._sceneSourceFile = null;
1230
+ this._sceneSource = this._sceneSourceInput = null;
1200
1231
 
1201
1232
  try {
1202
1233
 
@@ -64,9 +64,30 @@ export async function fileIdentity( file ) {
64
64
 
65
65
  }
66
66
 
67
+ /**
68
+ * A folder's identity: its name, total size, newest change and a SHA-256 over every file's path, size and date. Reads
69
+ * no file, and changes with any change inside the folder.
70
+ * @param {{name: string, files: Array<{path: string, file: Blob}>}} folder - from `localFolder`
71
+ * @returns {Promise<{name: string, size: number, lastModified: number, sample: string, files: number}>}
72
+ */
73
+ export async function folderIdentity( folder ) {
74
+
75
+ let size = 0;
76
+ let lastModified = 0;
77
+ const lines = folder.files.map( ( { path, file } ) => {
78
+
79
+ size += file.size;
80
+ lastModified = Math.max( lastModified, file.lastModified ?? 0 );
81
+ return `${path}|${file.size}|${file.lastModified ?? 0}`;
82
+
83
+ } );
84
+ return { name: folder.name, size, lastModified, sample: await sha256Hex( lines.join( '\n' ) ), files: folder.files.length };
85
+
86
+ }
87
+
67
88
  export function identityKey( identity ) {
68
89
 
69
- return `file:${identity.name}|${identity.size}|${identity.lastModified}|${identity.sample}`;
90
+ return `${identity.files === undefined ? 'file' : 'folder'}:${identity.name}|${identity.size}|${identity.lastModified}|${identity.sample}`;
70
91
 
71
92
  }
72
93
 
@@ -3,7 +3,7 @@ export {
3
3
  } from './StorageManager.js';
4
4
  export { openStorage, acquireSharedStorage } from './openStorage.js';
5
5
  export { sharedStorage } from './shared.js';
6
- export { fileIdentity, identityKey, sameIdentity, sampleHash, sha256Hex } from './identity.js';
6
+ export { fileIdentity, folderIdentity, identityKey, sameIdentity, sampleHash, sha256Hex } from './identity.js';
7
7
  export { DownloadCache, DOWNLOAD_POLICY, fetchFile, nameFromUrl, cachedObjectURL, sharedDownloads } from './DownloadCache.js';
8
8
  export { acquireLock, heldLockNames } from './locks.js';
9
9
  export { SpillStore } from './SpillStore.js';
@@ -108,9 +108,9 @@ const makeEvaluateMaterialResponse = ( deltaOnly ) => Fn( ( [ material, dots ],
108
108
  } ).ElseIf( material.roughness.greaterThan( 0.0 ), isotropic );
109
109
  else If( material.roughness.greaterThan( 0.0 ), isotropic );
110
110
 
111
- // Compensation factor and total directional albedo from the same table fetch.
111
+ // Metalness 0: the diffuse lobe loses only the non-metal share's albedo; (1 − metalness) below removes the metal's.
112
112
  const dfg = DFGResult.wrap( evaluateSpecularDFG(
113
- bf.f0, bf.f90, bf.eta, bf.F0m, material.metalness, iridF, material.iridescence, F0,
113
+ bf.f0, bf.f90, bf.eta, bf.F0m, float( 0.0 ), iridF, material.iridescence, F0,
114
114
  dots.NoV, material.roughness,
115
115
  ) );
116
116
  const specular = ( deltaOnly ? F : specularSS ).mul( dfg.compensation );
@@ -210,8 +210,9 @@ export const evaluateDiffuseTransmission = Fn( ( [ material, NoV ], builder ) =>
210
210
  F0.assign( mix( F0, iridF, material.iridescence ) );
211
211
 
212
212
  } );
213
+ // Metalness 0, as for the reflected diffuse lobe.
213
214
  const dfg = DFGResult.wrap( evaluateSpecularDFG(
214
- bf.f0, bf.f90, bf.eta, bf.F0m, material.metalness, iridF, material.iridescence, F0,
215
+ bf.f0, bf.f90, bf.eta, bf.F0m, float( 0.0 ), iridF, material.iridescence, F0,
215
216
  NoV, material.roughness,
216
217
  ) );
217
218
  kD.mulAssign( vec3( 1.0 ).sub( dfg.E_total ) );
package/src/core.js CHANGED
@@ -22,7 +22,7 @@ export { configureAssets, getAssetConfig } from './AssetConfig.js';
22
22
  export { configurePlatform, getPlatform } from './Platform.js';
23
23
  export { LightManager } from './managers/LightManager.js';
24
24
  export { listViewTransforms, getViewTransform, onRegistryChange, DEFAULT_VIEW } from './Color/ViewTransforms.js';
25
- export { ARCHIVE_FORMATS } from './Processor/archiveFormats.js';
25
+ export { ARCHIVE_FORMATS, localFolder } from './Processor/archiveFormats.js';
26
26
  export { ENGINE_DEFAULTS, MATERIAL_DEFAULTS } from './EngineDefaults.js';
27
27
  export { SKY_DEFAULTS } from './managers/EnvironmentManager.js';
28
28
  export { MAX_RESERVABLE_RENDER_SIZE } from './Processor/StorageTexturePool.js';
package/src/index.js CHANGED
@@ -30,13 +30,13 @@ export { configurePlatform, getPlatform } from './Platform.js';
30
30
 
31
31
  // On-disk storage (origin private file system): caches, and areas a host defines for its own data
32
32
  export {
33
- openStorage, StorageManager, STORAGE_KIND, ENGINE_AREAS, fileIdentity, identityKey, sameIdentity,
33
+ openStorage, StorageManager, STORAGE_KIND, ENGINE_AREAS, fileIdentity, folderIdentity, identityKey, sameIdentity,
34
34
  DownloadCache, DOWNLOAD_POLICY, fetchFile, nameFromUrl, cachedObjectURL, acquireLock, heldLockNames,
35
35
  } from './Storage/index.js';
36
36
 
37
37
  // Archives read in place: one entry at a time, never the whole file in memory
38
38
  export { openZip, readZipDirectory } from './Processor/ZipReader.js';
39
- export { ARCHIVE_FORMATS } from './Processor/archiveFormats.js';
39
+ export { ARCHIVE_FORMATS, localFolder } from './Processor/archiveFormats.js';
40
40
 
41
41
  // Engine package version, as built
42
42
  export { VERSION } from './version.js';
@@ -1,94 +0,0 @@
1
- //#region src/Processor/SceneMetadata.js
2
- var e = [
3
- "sourceFile",
4
- "url",
5
- "file"
6
- ];
7
- function t(e) {
8
- if (typeof e == "string") try {
9
- let t = JSON.parse(e);
10
- return t && typeof t == "object" ? t : null;
11
- } catch {
12
- return null;
13
- }
14
- return e && typeof e == "object" ? e : null;
15
- }
16
- function n(e) {
17
- let t = typeof e == "string" ? parseFloat(e) : e;
18
- return Number.isFinite(t) ? t : void 0;
19
- }
20
- function r(e) {
21
- let n = t(e);
22
- if (!n) return null;
23
- let r = (e) => e && (e.environment !== void 0 || e.render !== void 0), i = t(n.rayzee);
24
- return r(i) ? i : r(n) ? n : null;
25
- }
26
- function i(r) {
27
- let i = t(r);
28
- if (!i) return null;
29
- let a = e.map((e) => i[e]).find((e) => typeof e == "string" && e.trim());
30
- if (!a) return null;
31
- let o = n(i.rotation), s = n(i.intensity), c = { sourceFile: a.trim() };
32
- return o !== void 0 && (c.rotation = o), s !== void 0 && (c.intensity = Math.max(0, s)), c;
33
- }
34
- var a = [
35
- "maxBounces",
36
- "samples",
37
- "width",
38
- "height"
39
- ];
40
- function o(e) {
41
- let r = t(e);
42
- if (!r) return null;
43
- let i = {};
44
- for (let e of a) {
45
- let t = n(r[e]);
46
- t !== void 0 && t > 0 && (i[e] = Math.round(t));
47
- }
48
- return Object.keys(i).length ? i : null;
49
- }
50
- function s(e) {
51
- let t = r(e);
52
- if (!t) return null;
53
- let n = i(t.environment), a = o(t.render);
54
- return !n && !a ? null : {
55
- ...n ? { environment: n } : {},
56
- ...a ? { render: a } : {}
57
- };
58
- }
59
- function c(e) {
60
- if (!e) return null;
61
- let t = [
62
- e.userData,
63
- e.asset?.extras,
64
- e.scene?.userData
65
- ];
66
- Array.isArray(e.scenes) && t.push(...e.scenes.map((e) => e?.userData));
67
- for (let e of t) {
68
- let t = s(e);
69
- if (t) return t;
70
- }
71
- return null;
72
- }
73
- //#endregion
74
- //#region src/Processor/archiveFormats.js
75
- var l = Object.freeze({
76
- zip: {
77
- type: "archive",
78
- name: "ZIP Archive"
79
- },
80
- gz: {
81
- type: "archive",
82
- name: "Gzipped TAR Archive"
83
- },
84
- tgz: {
85
- type: "archive",
86
- name: "Gzipped TAR Archive"
87
- },
88
- tar: {
89
- type: "archive",
90
- name: "TAR Archive"
91
- }
92
- });
93
- //#endregion
94
- export { c as n, s as r, l as t };