@loaders.gl/scene 5.0.0-beta.2 → 5.0.0-beta.4

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 (151) hide show
  1. package/dist/dist.dev.js +3393 -407
  2. package/dist/dist.min.js +24 -16
  3. package/dist/draco/lib/utils/version.cjs +1 -1
  4. package/dist/draco/lib/utils/version.js +1 -1
  5. package/dist/draco-worker-node.js +415 -54
  6. package/dist/draco-worker-node.js.map +4 -4
  7. package/dist/draco-worker.js +390 -54
  8. package/dist/draco-worker.js.map +4 -4
  9. package/dist/draco-writer-worker-node.cjs +1401 -67
  10. package/dist/draco-writer-worker-node.cjs.map +4 -4
  11. package/dist/draco-writer-worker.js +1345 -67
  12. package/dist/draco-writer-worker.js.map +4 -4
  13. package/dist/gltf/gltf-loader-types.cjs.map +2 -2
  14. package/dist/gltf/gltf-loader-types.d.ts +6 -0
  15. package/dist/gltf/gltf-loader-types.d.ts.map +1 -1
  16. package/dist/gltf/gltf-loader-types.js.map +1 -1
  17. package/dist/gltf/index.cjs +2 -0
  18. package/dist/gltf/index.cjs.map +2 -2
  19. package/dist/gltf/index.d.ts +2 -2
  20. package/dist/gltf/index.d.ts.map +1 -1
  21. package/dist/gltf/index.js +1 -1
  22. package/dist/gltf/index.js.map +1 -1
  23. package/dist/gltf/lib/api/gltf-extensions.cjs +7 -2
  24. package/dist/gltf/lib/api/gltf-extensions.cjs.map +2 -2
  25. package/dist/gltf/lib/api/gltf-extensions.d.ts.map +1 -1
  26. package/dist/gltf/lib/api/gltf-extensions.js +7 -5
  27. package/dist/gltf/lib/api/gltf-extensions.js.map +1 -1
  28. package/dist/gltf/lib/extensions/EXT_texture_webp.cjs +1 -0
  29. package/dist/gltf/lib/extensions/EXT_texture_webp.cjs.map +2 -2
  30. package/dist/gltf/lib/extensions/EXT_texture_webp.d.ts.map +1 -1
  31. package/dist/gltf/lib/extensions/EXT_texture_webp.js +3 -0
  32. package/dist/gltf/lib/extensions/EXT_texture_webp.js.map +1 -1
  33. package/dist/gltf/lib/extensions/KHR_accessor_float64.cjs +45 -0
  34. package/dist/gltf/lib/extensions/KHR_accessor_float64.cjs.map +7 -0
  35. package/dist/gltf/lib/extensions/KHR_accessor_float64.d.ts +6 -0
  36. package/dist/gltf/lib/extensions/KHR_accessor_float64.d.ts.map +1 -0
  37. package/dist/gltf/lib/extensions/KHR_accessor_float64.js +20 -0
  38. package/dist/gltf/lib/extensions/KHR_accessor_float64.js.map +1 -0
  39. package/dist/gltf/lib/extensions/KHR_gaussian_splatting.cjs +12 -3
  40. package/dist/gltf/lib/extensions/KHR_gaussian_splatting.cjs.map +2 -2
  41. package/dist/gltf/lib/extensions/KHR_gaussian_splatting.d.ts +2 -1
  42. package/dist/gltf/lib/extensions/KHR_gaussian_splatting.d.ts.map +1 -1
  43. package/dist/gltf/lib/extensions/KHR_gaussian_splatting.js +9 -3
  44. package/dist/gltf/lib/extensions/KHR_gaussian_splatting.js.map +1 -1
  45. package/dist/gltf/lib/extensions/MSFT_texture_dds.cjs +64 -0
  46. package/dist/gltf/lib/extensions/MSFT_texture_dds.cjs.map +7 -0
  47. package/dist/gltf/lib/extensions/MSFT_texture_dds.d.ts +12 -0
  48. package/dist/gltf/lib/extensions/MSFT_texture_dds.d.ts.map +1 -0
  49. package/dist/gltf/lib/extensions/MSFT_texture_dds.js +39 -0
  50. package/dist/gltf/lib/extensions/MSFT_texture_dds.js.map +1 -0
  51. package/dist/gltf/lib/extensions/utils/3d-tiles-utils.cjs +1 -1
  52. package/dist/gltf/lib/extensions/utils/3d-tiles-utils.cjs.map +2 -2
  53. package/dist/gltf/lib/extensions/utils/3d-tiles-utils.d.ts.map +1 -1
  54. package/dist/gltf/lib/extensions/utils/3d-tiles-utils.js +3 -1
  55. package/dist/gltf/lib/extensions/utils/3d-tiles-utils.js.map +1 -1
  56. package/dist/gltf/lib/parsers/parse-gltf.cjs +25 -0
  57. package/dist/gltf/lib/parsers/parse-gltf.cjs.map +2 -2
  58. package/dist/gltf/lib/parsers/parse-gltf.d.ts.map +1 -1
  59. package/dist/gltf/lib/parsers/parse-gltf.js +18 -0
  60. package/dist/gltf/lib/parsers/parse-gltf.js.map +1 -1
  61. package/dist/gltf/lib/types/gltf-ext-gaussian-splatting-schema.cjs.map +1 -1
  62. package/dist/gltf/lib/types/gltf-ext-gaussian-splatting-schema.d.ts +1 -1
  63. package/dist/gltf/lib/types/gltf-ext-gaussian-splatting-schema.d.ts.map +1 -1
  64. package/dist/gltf/lib/types/gltf-texture-procedurals.cjs +19 -0
  65. package/dist/gltf/lib/types/gltf-texture-procedurals.cjs.map +7 -0
  66. package/dist/gltf/lib/types/gltf-texture-procedurals.d.ts +45 -0
  67. package/dist/gltf/lib/types/gltf-texture-procedurals.d.ts.map +1 -0
  68. package/dist/gltf/lib/types/gltf-texture-procedurals.js +5 -0
  69. package/dist/gltf/lib/types/gltf-texture-procedurals.js.map +1 -0
  70. package/dist/gltf/lib/types/gltf-types.cjs.map +1 -1
  71. package/dist/gltf/lib/types/gltf-types.d.ts +7 -0
  72. package/dist/gltf/lib/types/gltf-types.d.ts.map +1 -1
  73. package/dist/gltf/lib/types/gltf-zod-schema.cjs +3 -0
  74. package/dist/gltf/lib/types/gltf-zod-schema.cjs.map +2 -2
  75. package/dist/gltf/lib/types/gltf-zod-schema.d.ts +5 -0
  76. package/dist/gltf/lib/types/gltf-zod-schema.d.ts.map +1 -1
  77. package/dist/gltf/lib/types/gltf-zod-schema.js +4 -0
  78. package/dist/gltf/lib/types/gltf-zod-schema.js.map +1 -1
  79. package/dist/gltf/lib/utils/version.cjs +1 -1
  80. package/dist/gltf/lib/utils/version.js +1 -1
  81. package/dist/gltf/schema.cjs +3 -0
  82. package/dist/gltf/schema.cjs.map +2 -2
  83. package/dist/gltf/schema.d.ts +1 -0
  84. package/dist/gltf/schema.d.ts.map +1 -1
  85. package/dist/gltf/schema.js +1 -0
  86. package/dist/gltf/schema.js.map +1 -1
  87. package/dist/gltf-loader-types.cjs.map +2 -2
  88. package/dist/index.cjs +3 -0
  89. package/dist/index.cjs.map +2 -2
  90. package/dist/index.d.ts +2 -0
  91. package/dist/index.d.ts.map +1 -1
  92. package/dist/index.js +1 -0
  93. package/dist/index.js.map +1 -1
  94. package/dist/materialx/parse-materialx.cjs +61 -0
  95. package/dist/materialx/parse-materialx.cjs.map +7 -0
  96. package/dist/materialx/parse-materialx.d.ts +23 -0
  97. package/dist/materialx/parse-materialx.d.ts.map +1 -0
  98. package/dist/materialx/parse-materialx.js +39 -0
  99. package/dist/materialx/parse-materialx.js.map +1 -0
  100. package/dist/materialx/procedural-graph.cjs +77 -0
  101. package/dist/materialx/procedural-graph.cjs.map +7 -0
  102. package/dist/materialx/procedural-graph.d.ts +40 -0
  103. package/dist/materialx/procedural-graph.d.ts.map +1 -0
  104. package/dist/materialx/procedural-graph.js +59 -0
  105. package/dist/materialx/procedural-graph.js.map +1 -0
  106. package/dist/materialx-loader-types.cjs +57 -0
  107. package/dist/materialx-loader-types.cjs.map +7 -0
  108. package/dist/materialx-loader-types.d.ts +34 -0
  109. package/dist/materialx-loader-types.d.ts.map +1 -0
  110. package/dist/materialx-loader-types.js +20 -0
  111. package/dist/materialx-loader-types.js.map +1 -0
  112. package/dist/materialx-loader.cjs +40 -0
  113. package/dist/materialx-loader.cjs.map +7 -0
  114. package/dist/materialx-loader.d.ts +19 -0
  115. package/dist/materialx-loader.d.ts.map +1 -0
  116. package/dist/materialx-loader.js +14 -0
  117. package/dist/materialx-loader.js.map +1 -0
  118. package/dist/mtl-loader-types.cjs +1 -1
  119. package/dist/obj/mtl-loader-types.cjs +1 -1
  120. package/dist/obj/mtl-loader-types.js +1 -1
  121. package/dist/obj/obj-loader-types.cjs +1 -1
  122. package/dist/obj/obj-loader-types.js +1 -1
  123. package/dist/obj/obj-writer.cjs +1 -1
  124. package/dist/obj/obj-writer.js +1 -1
  125. package/dist/obj-loader-types.cjs +1 -1
  126. package/dist/obj-worker.js +393 -57
  127. package/dist/obj-writer.cjs +1 -1
  128. package/dist/usd/usd-loader-types.cjs +1 -1
  129. package/dist/usd/usd-loader-types.js +1 -1
  130. package/dist/usd-loader-types.cjs +1 -1
  131. package/package.json +11 -5
  132. package/src/gltf/gltf-loader-types.ts +6 -0
  133. package/src/gltf/index.ts +4 -1
  134. package/src/gltf/lib/api/gltf-extensions.ts +7 -2
  135. package/src/gltf/lib/extensions/EXT_texture_webp.ts +3 -0
  136. package/src/gltf/lib/extensions/KHR_accessor_float64.ts +22 -0
  137. package/src/gltf/lib/extensions/KHR_gaussian_splatting.ts +17 -3
  138. package/src/gltf/lib/extensions/MSFT_texture_dds.ts +52 -0
  139. package/src/gltf/lib/extensions/utils/3d-tiles-utils.ts +5 -1
  140. package/src/gltf/lib/parsers/parse-gltf.ts +29 -0
  141. package/src/gltf/lib/types/gltf-ext-gaussian-splatting-schema.ts +1 -1
  142. package/src/gltf/lib/types/gltf-texture-procedurals.ts +67 -0
  143. package/src/gltf/lib/types/gltf-types.ts +8 -0
  144. package/src/gltf/lib/types/gltf-zod-schema.ts +5 -0
  145. package/src/gltf/schema.ts +1 -0
  146. package/src/index.ts +3 -0
  147. package/src/materialx/README.md +5 -0
  148. package/src/materialx/parse-materialx.ts +70 -0
  149. package/src/materialx/procedural-graph.ts +94 -0
  150. package/src/materialx-loader-types.ts +24 -0
  151. package/src/materialx-loader.ts +15 -0
@@ -27,7 +27,7 @@ module.exports = __toCommonJS(obj_writer_exports);
27
27
  // src/obj/obj-writer.ts
28
28
  var import_schema_utils = require("@loaders.gl/core/schema-utils");
29
29
  var import_obj_format = require("./obj-format.cjs");
30
- var VERSION = true ? "5.0.0-beta.2" : "latest";
30
+ var VERSION = true ? "5.0.0-beta.4" : "latest";
31
31
  var OBJWriter = {
32
32
  ...import_obj_format.OBJFormat,
33
33
  dataType: null,
@@ -33,7 +33,7 @@ __export(usd_loader_types_exports, {
33
33
  USDLoader: () => USDLoader
34
34
  });
35
35
  module.exports = __toCommonJS(usd_loader_types_exports);
36
- var VERSION = true ? "5.0.0-beta.2" : "latest";
36
+ var VERSION = true ? "5.0.0-beta.4" : "latest";
37
37
  async function preload() {
38
38
  const { USDLoaderWithParser } = await import("@loaders.gl/scene/usd-loader");
39
39
  return USDLoaderWithParser;
@@ -3,7 +3,7 @@
3
3
  // Copyright (c) vis.gl contributors
4
4
  // __VERSION__ is injected by babel-plugin-version-inline
5
5
  // @ts-ignore TS2304: Cannot find name '__VERSION__'.
6
- const VERSION = typeof "5.0.0-beta.2" !== 'undefined' ? "5.0.0-beta.2" : 'latest';
6
+ const VERSION = typeof "5.0.0-beta.4" !== 'undefined' ? "5.0.0-beta.4" : 'latest';
7
7
  /** Loads the parser-bearing USD loader implementation. */
8
8
  async function preload() {
9
9
  const { USDLoaderWithParser } = await import('@loaders.gl/scene/usd-loader');
@@ -35,7 +35,7 @@ __export(usd_loader_types_exports, {
35
35
  module.exports = __toCommonJS(usd_loader_types_exports);
36
36
 
37
37
  // src/usd/usd-loader-types.ts
38
- var VERSION = true ? "5.0.0-beta.2" : "latest";
38
+ var VERSION = true ? "5.0.0-beta.4" : "latest";
39
39
  async function preload() {
40
40
  const { USDLoaderWithParser } = await import("@loaders.gl/scene/usd-loader");
41
41
  return USDLoaderWithParser;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loaders.gl/scene",
3
- "version": "5.0.0-beta.2",
3
+ "version": "5.0.0-beta.4",
4
4
  "description": "glTF, GLB, OBJ, MTL, OpenUSD, and Draco geometry loaders and writers",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -236,6 +236,11 @@
236
236
  "./draco-library-options": {
237
237
  "types": "./dist/draco-library-options.d.ts",
238
238
  "import": "./dist/draco-library-options.js"
239
+ },
240
+ "./materialx-loader": {
241
+ "types": "./dist/materialx-loader.d.ts",
242
+ "import": "./dist/materialx-loader.js",
243
+ "require": "./dist/materialx-loader.cjs"
239
244
  }
240
245
  },
241
246
  "sideEffects": false,
@@ -270,9 +275,10 @@
270
275
  "@loaders.gl/core": "~5.0.0-alpha.0"
271
276
  },
272
277
  "dependencies": {
273
- "@loaders.gl/images": "5.0.0-beta.2",
274
- "@math.gl/core": "5.0.0-beta.2",
275
- "@math.gl/geometry": "5.0.0-beta.2",
278
+ "@loaders.gl/documents": "5.0.0-beta.4",
279
+ "@loaders.gl/images": "5.0.0-beta.4",
280
+ "@math.gl/core": "5.0.0-beta.4",
281
+ "@math.gl/geometry": "5.0.0-beta.4",
276
282
  "zod": "^4.1.12"
277
283
  },
278
284
  "devDependencies": {
@@ -281,5 +287,5 @@
281
287
  "optionalDependencies": {
282
288
  "draco3d": "1.5.7"
283
289
  },
284
- "gitHead": "d259e5bc74caf8d75e808314b7fef2fa1bd70ff7"
290
+ "gitHead": "c9420f06e870fa353889d55b684e3588d24574c2"
285
291
  }
@@ -22,6 +22,12 @@ export type GLTFLoaderOptions = StrictLoaderOptions &
22
22
  GLBLoaderOptions &
23
23
  DracoLoaderOptions & {
24
24
  gltf?: ParseGLTFOptions;
25
+ /** Options forwarded to an injected SPZ loader. The source frame is always LUF for glTF. */
26
+ splats?: {
27
+ shape?: 'arrow-table';
28
+ sourceCoordinateSystem?: 'RUB' | 'LUF' | 'RUF' | 'UNSPECIFIED';
29
+ targetCoordinateSystem?: 'RUB' | 'LUF' | 'RUF' | 'UNSPECIFIED';
30
+ };
25
31
  };
26
32
 
27
33
  /** Preloads the parser-bearing glTF loader implementation. */
package/src/gltf/index.ts CHANGED
@@ -29,7 +29,9 @@ export type {
29
29
  GLTF_KHR_texture_basisu,
30
30
  GLTF_KHR_meshopt_compression,
31
31
  GLTF_EXT_meshopt_compression,
32
- GLTF_EXT_texture_webp
32
+ GLTF_EXT_texture_webp,
33
+ GLTF_EXT_texture_avif,
34
+ GLTF_MSFT_texture_dds
33
35
  } from './lib/types/gltf-json-schema';
34
36
 
35
37
  export type {GLTFShape, GLTFBoundingVolume} from './lib/types/gltf-shape-schema';
@@ -170,6 +172,7 @@ export {
170
172
  GLTFKHRMeshoptCompressionSchema,
171
173
  GLTFEXTMeshoptCompressionSchema,
172
174
  GLTFEXTTextureWebpSchema,
175
+ GLTFEXTTextureAvifSchema,
173
176
  GLTFMSFTTextureDdsSchema,
174
177
  GLTFShapeSchema,
175
178
  GLTFBoundingVolumeSchema
@@ -1,3 +1,4 @@
1
+ import * as KHR_accessor_float64 from '../extensions/KHR_accessor_float64';
1
2
  // loaders.gl
2
3
  // SPDX-License-Identifier: MIT
3
4
  // Copyright (c) vis.gl contributors
@@ -25,6 +26,7 @@ import * as EXT_meshopt_compression from '../extensions/EXT_meshopt_compression'
25
26
  import * as KHR_meshopt_compression from '../extensions/KHR_meshopt_compression';
26
27
  import * as EXT_texture_webp from '../extensions/EXT_texture_webp';
27
28
  import * as EXT_texture_avif from '../extensions/EXT_texture_avif';
29
+ import * as MSFT_texture_dds from '../extensions/MSFT_texture_dds';
28
30
  import * as KHR_texture_basisu from '../extensions/KHR_texture_basisu';
29
31
  import * as KHR_draco_mesh_compression from '../extensions/KHR_draco_mesh_compression';
30
32
  import * as KHR_texture_transform from '../extensions/KHR_texture_transform';
@@ -60,6 +62,7 @@ type GLTFExtensionPlugin = {
60
62
  * These are just extensions that can be handled fully or partially during loading.
61
63
  */
62
64
  export const EXTENSIONS: GLTFExtensionPlugin[] = [
65
+ KHR_accessor_float64,
63
66
  // 1.0
64
67
  // KHR_binary_gltf is handled separately - must be processed before other parsing starts
65
68
  // KHR_binary_gltf,
@@ -79,9 +82,11 @@ export const EXTENSIONS: GLTFExtensionPlugin[] = [
79
82
  EXT_mesh_polygon,
80
83
  MPEG_audio_spatial,
81
84
  KHR_audio_emitter,
82
- EXT_texture_avif,
83
85
  EXT_texture_webp,
84
- // Basisu should come after webp, we want basisu to be preferred if both are provided
86
+ EXT_texture_avif,
87
+ // Compressed textures take precedence over browser image formats when available.
88
+ MSFT_texture_dds,
89
+ // BasisU remains preferred when both compressed alternatives are provided.
85
90
  KHR_texture_basisu,
86
91
  KHR_lights_punctual,
87
92
  KHR_materials_unlit,
@@ -25,6 +25,9 @@ export const name = EXT_TEXTURE_WEBP;
25
25
  export function preprocess(gltfData: GLTFWithBuffers, options: GLTFLoaderOptions): void {
26
26
  const iterator = new GLTFIterator(gltfData);
27
27
 
28
+ // Avoid probing image capabilities for unrelated documents, including worker environments.
29
+ if (!iterator.hasExtension(EXT_TEXTURE_WEBP)) return;
30
+
28
31
  if (!isImageFormatSupported('image/webp')) {
29
32
  if (iterator.isExtensionRequired(EXT_TEXTURE_WEBP)) {
30
33
  throw new Error(`gltf: Required extension ${EXT_TEXTURE_WEBP} not supported by browser`);
@@ -0,0 +1,22 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright vis.gl contributors
4
+
5
+ import type {GLTFWithBuffers} from '../types/gltf-types';
6
+
7
+ /** Draft extension enabling binary64 accessor components. */
8
+ export const name = 'KHR_accessor_float64';
9
+
10
+ /** Validate the declared extension without converting or removing binary64 data. */
11
+ export function preprocess(gltf: GLTFWithBuffers): void {
12
+ const {json} = gltf;
13
+ if (!json.extensionsUsed?.includes(name) && !json.extensionsRequired?.includes(name)) return;
14
+ if (!json.extensionsUsed?.includes(name) || !json.extensionsRequired?.includes(name)) {
15
+ throw new Error(`${name}: must be declared in extensionsUsed and extensionsRequired.`);
16
+ }
17
+ for (const [index, accessor] of (json.accessors || []).entries()) {
18
+ if (accessor.componentType === 5130 && accessor.normalized) {
19
+ throw new Error(`${name}: accessor ${index} must not be normalized.`);
20
+ }
21
+ }
22
+ }
@@ -4,6 +4,8 @@
4
4
 
5
5
  /* eslint-disable camelcase */
6
6
 
7
+ import {parseFromContext} from '@loaders.gl/core/loader-utils';
8
+ import type {LoaderContext} from '@loaders.gl/core/loader-utils';
7
9
  import type {GLTF, GLTFMeshPrimitive} from '../types/gltf-json-schema';
8
10
  import type {GLTFWithBuffers} from '../types/gltf-types';
9
11
  import type {GLTFLoaderOptions} from '../../gltf-loader-types';
@@ -28,7 +30,12 @@ const REQUIRED_ATTRIBUTES = [
28
30
  ] as const;
29
31
 
30
32
  /** Validates Gaussian splat primitives while preserving all source JSON. */
31
- export async function decode(gltfData: GLTFWithBuffers, options: GLTFLoaderOptions): Promise<void> {
33
+ export async function decode(
34
+ gltfData: GLTFWithBuffers,
35
+ options: GLTFLoaderOptions,
36
+ context?: LoaderContext
37
+ ): Promise<void> {
38
+ const loader = context?.loaders?.find(candidate => candidate.extensions?.includes('spz'));
32
39
  const descriptors = getGaussianSplatPrimitives(gltfData);
33
40
  const iterator = new GLTFIterator(gltfData);
34
41
  for (const [meshIndex, mesh] of (gltfData.json.meshes || []).entries()) {
@@ -53,12 +60,19 @@ export async function decode(gltfData: GLTFWithBuffers, options: GLTFLoaderOptio
53
60
  const bufferView = gltfData.json.bufferViews?.[compression.bufferView];
54
61
  if (bufferView && gltfData.buffers[bufferView.buffer]) {
55
62
  descriptor.compressedBytes = getBufferViewBytes(gltfData, compression.bufferView);
56
- } else if (decoder) {
63
+ } else if (decoder || loader) {
57
64
  throw new Error(
58
65
  `KHR_gaussian_splatting: bufferView ${compression.bufferView} is not loaded for SPZ2 decoding.`
59
66
  );
60
67
  }
61
- if (decoder && descriptor.compressedBytes) {
68
+ if (loader && context && descriptor.compressedBytes) {
69
+ descriptor.decoded = await parseFromContext(
70
+ descriptor.compressedBytes.buffer as ArrayBuffer,
71
+ loader,
72
+ {...options, splats: {...options.splats, sourceCoordinateSystem: 'LUF'}},
73
+ context
74
+ );
75
+ } else if (decoder && descriptor.compressedBytes) {
62
76
  descriptor.decoded = await decoder(descriptor.compressedBytes.buffer as ArrayBuffer, {
63
77
  sourceCoordinateSystem: 'LUF'
64
78
  });
@@ -0,0 +1,52 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type {GLTFLoaderOptions} from '../../gltf-loader-types';
6
+ import type {GLTFWithBuffers} from '../types/gltf-types';
7
+ import type {GLTF_MSFT_texture_dds} from '../types/gltf-json-schema';
8
+ import type {Loader, LoaderContext} from '@loaders.gl/core/loader-utils';
9
+ import {GLTFIterator} from '../api/gltf-iterator';
10
+
11
+ /** Name of the Microsoft DDS texture extension. */
12
+ export const name = 'MSFT_texture_dds';
13
+
14
+ /** Finds a DDS-capable loader supplied through the parent loader context. */
15
+ export function getDDSLoader(context?: LoaderContext): Loader | undefined {
16
+ return context?.loaders?.find(
17
+ loader => loader.extensions?.includes('dds') || loader.mimeTypes?.includes('image/vnd-ms.dds')
18
+ );
19
+ }
20
+
21
+ /** Select DDS sources only when an application supplies a compatible loader. */
22
+ export function preprocess(
23
+ gltf: GLTFWithBuffers,
24
+ _options: GLTFLoaderOptions,
25
+ context?: LoaderContext
26
+ ): void {
27
+ const iterator = new GLTFIterator(gltf);
28
+ if (!iterator.hasExtension(name)) return;
29
+ if (!getDDSLoader(context)) {
30
+ if (iterator.isExtensionRequired(name)) {
31
+ throw new Error('gltf: Required extension MSFT_texture_dds needs a DDS parser');
32
+ }
33
+ return;
34
+ }
35
+ for (const texture of iterator.textures) {
36
+ const extension = iterator.getExtension<GLTF_MSFT_texture_dds>(texture, name);
37
+ if (extension) texture.source = extension.source;
38
+ }
39
+ }
40
+
41
+ /** Remove DDS declarations only after image loading can identify the selected sources. */
42
+ export async function decode(
43
+ gltf: GLTFWithBuffers,
44
+ options: GLTFLoaderOptions,
45
+ context?: LoaderContext
46
+ ): Promise<void> {
47
+ if (!getDDSLoader(context) || options.gltf?.loadImages === false) return;
48
+ const iterator = new GLTFIterator(gltf);
49
+ if (!iterator.hasExtension(name)) return;
50
+ for (const texture of iterator.textures) iterator.removeExtension(texture, name);
51
+ iterator.removeExtension(name);
52
+ }
@@ -197,7 +197,11 @@ export function getPrimitiveTextureData(
197
197
  const mimeType = json.images?.[imageIndex]?.mimeType;
198
198
  const parsedImage = scenegraph.gltf.images?.[imageIndex];
199
199
  // Checking for width is to prevent handling Un-processed images (e.g. [analyze] stage, where loadImages option is set to false)
200
- if (parsedImage && typeof parsedImage.width !== 'undefined') {
200
+ if (
201
+ parsedImage &&
202
+ typeof parsedImage.width !== 'undefined' &&
203
+ !('compressed' in parsedImage && parsedImage.compressed)
204
+ ) {
201
205
  const textureData: number[] = [];
202
206
  for (let index = 0; index < textureCoordinates.length; index += 2) {
203
207
  const value = getImageValueByCoordinates(
@@ -21,6 +21,7 @@ import {canonicalizeUrl, resolveUrl} from '../gltf-utils/resolve-url';
21
21
  import {findGLTFFileIndex, resolveGLTFFile} from '../gltf-utils/resolve-gltf-file';
22
22
  import {getTypedArrayForBufferView} from '../gltf-utils/get-typed-array';
23
23
  import {preprocessExtensions, decodeExtensions} from '../api/gltf-extensions';
24
+ import {getDDSLoader} from '../extensions/MSFT_texture_dds';
24
25
  import {normalizeGLTFV1WithDeferredBuffers} from '../api/normalize-gltf-v1';
25
26
 
26
27
  /** */
@@ -542,6 +543,34 @@ async function loadImage(
542
543
 
543
544
  const gltfOptions = getGLTFImageOptions(options, image.mimeType);
544
545
 
546
+ const ddsLoader = getDDSLoader(context);
547
+ const ddsSelected = Boolean(
548
+ ddsLoader &&
549
+ !options.gltf?.excludeExtensions?.includes('MSFT_texture_dds') &&
550
+ gltf.json.textures?.some(
551
+ texture =>
552
+ texture.source === index && texture.extensions?.MSFT_texture_dds?.source === index
553
+ )
554
+ );
555
+ if (ddsSelected) {
556
+ const levels = (await parseFromContext(
557
+ arrayBuffer,
558
+ ddsLoader!,
559
+ options,
560
+ context
561
+ )) as TextureLevel[];
562
+ assert(levels.length > 0, 'MSFT_texture_dds parser returned no texture levels');
563
+ gltf.images = gltf.images || [];
564
+ gltf.images[index] = {
565
+ compressed: true,
566
+ mipmaps: true,
567
+ width: levels[0].width,
568
+ height: levels[0].height,
569
+ data: levels
570
+ };
571
+ return;
572
+ }
573
+
545
574
  // Call `parse`
546
575
  let parsedImage = (await parseFromContext(
547
576
  arrayBuffer,
@@ -41,6 +41,6 @@ export type GLTFGaussianSplatPrimitive = {
41
41
  compressedBufferView?: number;
42
42
  /** Preserved compressed SPZ2 bytes for native or GPU decoders. */
43
43
  compressedBytes?: Uint8Array;
44
- /** Result returned by an injected SPZ2 decoder, when one was supplied. */
44
+ /** Result returned by an injected SPZ loader or legacy decoder, when supplied. */
45
45
  decoded?: unknown;
46
46
  };
@@ -0,0 +1,67 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright vis.gl contributors
4
+
5
+ /** Serialized value types in the experimental procedural graph proposal. */
6
+ export type GLTFProceduralValueType =
7
+ | 'boolean'
8
+ | 'float'
9
+ | 'integer'
10
+ | 'color3'
11
+ | 'color4'
12
+ | 'vector2'
13
+ | 'vector3'
14
+ | 'vector4'
15
+ | 'integer2'
16
+ | 'integer3'
17
+ | 'integer4'
18
+ | 'matrix3x3'
19
+ | 'matrix4x4'
20
+ | 'string'
21
+ | 'filename';
22
+
23
+ /** Named graph port, retaining serialized connections without evaluating them. */
24
+ export interface GLTFProceduralPort {
25
+ /** Port category. */
26
+ nodetype: 'input' | 'output';
27
+ /** Declared value type. */
28
+ type: GLTFProceduralValueType;
29
+ /** Authored constant; scalar numeric arrays are retained as authored. */
30
+ value?: boolean | string | number | number[];
31
+ /** Upstream processing node index. */
32
+ node?: number;
33
+ /** Name of a graph interface input. */
34
+ input?: string;
35
+ /** Name of the selected upstream output. */
36
+ output?: string;
37
+ }
38
+
39
+ /** Processing node in a procedural graph. */
40
+ export interface GLTFProceduralNode {
41
+ /** Optional display name. */
42
+ name?: string;
43
+ /** MaterialX or custom node category; unknown categories are retained. */
44
+ nodetype: string;
45
+ /** Single output type, or multiple named outputs. */
46
+ type: GLTFProceduralValueType | 'multioutput';
47
+ /** Named input ports. */
48
+ inputs?: Record<string, GLTFProceduralPort>;
49
+ /** Named output ports. */
50
+ outputs: Record<string, GLTFProceduralPort>;
51
+ }
52
+
53
+ /** Flat procedural graph using the draft's named-port representation. */
54
+ export interface GLTFProceduralGraph extends GLTFProceduralNode {
55
+ /** Graph category. */
56
+ nodetype: 'nodegraph';
57
+ /** Processing nodes addressed by index. */
58
+ nodes: GLTFProceduralNode[];
59
+ }
60
+
61
+ /** Procedural output attached to a material texture-info object. */
62
+ export interface GLTFProceduralBinding {
63
+ /** Index into the root extension's procedurals array. */
64
+ index: number;
65
+ /** Selected output name; required for graphs with multiple outputs. */
66
+ output?: string;
67
+ }
@@ -5,6 +5,7 @@
5
5
  /* eslint-disable camelcase */
6
6
 
7
7
  import {ImageType} from '@loaders.gl/images';
8
+ import type {TextureLevel} from '@loaders.gl/core/schema';
8
9
  import type {GLTF} from './gltf-json-schema';
9
10
  import type {GLTFGaussianSplatPrimitive} from './gltf-ext-gaussian-splatting-schema';
10
11
  import type {GLTFSpatialAudio} from './gltf-mpeg-audio-spatial-schema';
@@ -50,6 +51,13 @@ export type GLTFExternalFile = GLTFExternalBuffer & {
50
51
 
51
52
  type GLTFExternalImage =
52
53
  | ImageType
54
+ | {
55
+ compressed: true;
56
+ mipmaps: true;
57
+ width: number;
58
+ height: number;
59
+ data: TextureLevel[];
60
+ }
53
61
  | {
54
62
  compressed: true;
55
63
  mipmaps: false;
@@ -539,6 +539,11 @@ export const GLTFEXTTextureWebpSchema = z
539
539
  .object({source: GLTFIdSchema, extras: z.unknown().optional()})
540
540
  .catchall(z.unknown());
541
541
 
542
+ /** Zod schema for the EXT_texture_avif texture source extension. */
543
+ export const GLTFEXTTextureAvifSchema = z
544
+ .object({source: GLTFIdSchema, extras: z.unknown().optional()})
545
+ .catchall(z.unknown());
546
+
542
547
  /** Zod schema for the MSFT_texture_dds extension. */
543
548
  export const GLTFMSFTTextureDdsSchema = z
544
549
  .object({source: GLTFIdSchema, extras: z.unknown().optional()})
@@ -22,3 +22,4 @@ export {
22
22
  export * from './lib/types/gltf-additional-extension-schemas';
23
23
  export * from './lib/types/gltf-audio-extension-schemas';
24
24
  export * from './lib/types/gltf-extension-schemas';
25
+ export {GLTFEXTTextureAvifSchema} from './lib/types/gltf-zod-schema';
package/src/index.ts CHANGED
@@ -20,3 +20,6 @@ export {DracoLoader, DracoWorkerLoader} from './draco/draco-loader-types';
20
20
  export {DracoFormat} from './draco/draco-format';
21
21
  export type * from './draco/index';
22
22
  export {DRACO_EXTERNAL_LIBRARIES, DRACO_EXTERNAL_LIBRARY_URLS} from './draco/draco-libraries';
23
+
24
+ export {MaterialXLoader} from './materialx-loader-types';
25
+ export type {MaterialXDocument, MaterialXElement} from './materialx/parse-materialx';
@@ -0,0 +1,5 @@
1
+ # MaterialX parser
2
+
3
+ Native XML parsing implementation for browsers and Node.js. `parseMaterialX` returns an ordered element tree retaining string attributes, named connections, custom node categories and unresolved includes. It rejects malformed XML, document types, and missing or unsupported major versions.
4
+
5
+ This implementation does not resolve libraries, validate MaterialX node signatures, evaluate graphs, or generate shaders. The scene package exports MaterialXLoader with a materialx-loader implementation subpath.
@@ -0,0 +1,70 @@
1
+ import {parseXMLSync} from '@loaders.gl/documents/xml-parser';
2
+ // loaders.gl
3
+ // SPDX-License-Identifier: MIT
4
+ // Copyright vis.gl contributors
5
+
6
+ /** Authored MaterialX element, including extension categories and connection attributes. */
7
+ export interface MaterialXElement {
8
+ /** XML element category, for example nodegraph, input, or multiply. */
9
+ category: string;
10
+ /** Authored string attributes; values are not coerced or evaluated. */
11
+ attributes: Record<string, string>;
12
+ /** Child elements in document order. */
13
+ children: MaterialXElement[];
14
+ }
15
+
16
+ /** Parsed MaterialX document. External includes remain unresolved. */
17
+ export interface MaterialXDocument {
18
+ /** Authored MaterialX version. */
19
+ version: string;
20
+ /** MaterialX root element. */
21
+ root: MaterialXElement;
22
+ }
23
+
24
+ /**
25
+ * Parses a MaterialX XML document using the native documents XML parser.
26
+ * Preserves unknown categories, connection references and value strings.
27
+ * Does not load includes, resolve node definitions, or evaluate shader graphs.
28
+ */
29
+ export function parseMaterialX(text: string): MaterialXDocument {
30
+ if (/<!DOCTYPE|<!ENTITY/i.test(text)) {
31
+ throw new Error('MaterialX: document types and entity declarations are unsupported.');
32
+ }
33
+ let element: OrderedXMLElement;
34
+ try {
35
+ element = parseXMLSync(text, {
36
+ preserveOrder: true,
37
+ parseAttributeValue: false,
38
+ trimValues: false
39
+ });
40
+ } catch (error) {
41
+ throw new Error('MaterialX: malformed XML.', {cause: error});
42
+ }
43
+ if (element.name !== 'materialx') {
44
+ throw new Error('MaterialX: expected a materialx root element.');
45
+ }
46
+ const version = element.attributes.version;
47
+ if (!version || !/^1\.\d+$/.test(version)) {
48
+ throw new Error('MaterialX: expected a MaterialX 1.x version.');
49
+ }
50
+ return {version, root: parseElement(element, 0)};
51
+ }
52
+
53
+ /** Ordered element representation returned by the XML parser. */
54
+ interface OrderedXMLElement {
55
+ /** XML element name. */
56
+ name: string;
57
+ /** Authored string attributes. */
58
+ attributes: Record<string, string>;
59
+ /** Ordered child elements. */
60
+ children: OrderedXMLElement[];
61
+ }
62
+
63
+ /** Converts the native XML tree to MaterialX categories. */
64
+ function parseElement(element: OrderedXMLElement, depth: number): MaterialXElement {
65
+ return {
66
+ category: element.name,
67
+ attributes: element.attributes,
68
+ children: element.children.map(child => parseElement(child, depth + 1))
69
+ };
70
+ }
@@ -0,0 +1,94 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ /** Typed connection to one node output. */
5
+ export interface ProceduralConnection {
6
+ /** Stable identifier of the upstream node. */
7
+ node: string;
8
+ /** Name of its output port. */
9
+ output: string;
10
+ }
11
+
12
+ /** Input supplied by a constant or another node. */
13
+ export interface ProceduralInput {
14
+ /** Declared value type. */
15
+ type: string;
16
+ /** Constant value, retained without implicit conversion. */
17
+ value?: unknown;
18
+ /** Optional upstream connection. */
19
+ connection?: ProceduralConnection;
20
+ }
21
+
22
+ /** Renderer-independent operation with explicitly declared ports. */
23
+ export interface ProceduralNode {
24
+ /** Stable node identifier, unique within the graph. */
25
+ id: string;
26
+ /** Operation identifier for a downstream implementation registry. */
27
+ operation: string;
28
+ /** Named inputs. */
29
+ inputs: Record<string, ProceduralInput>;
30
+ /** Named output value types. */
31
+ outputs: Record<string, string>;
32
+ }
33
+
34
+ /** Graph contract independent of GPU resources or shader languages. */
35
+ export interface ProceduralGraph {
36
+ /** Nodes in authored order. */
37
+ nodes: ProceduralNode[];
38
+ /** Named graph outputs and their upstream connections. */
39
+ outputs: Record<string, ProceduralConnection>;
40
+ }
41
+
42
+ /**
43
+ * Validates explicit references and exact port types, returning dependency-first nodes.
44
+ * Does not infer conversions, resolve MaterialX definitions, or evaluate operations.
45
+ */
46
+ export function orderProceduralGraph(graph: ProceduralGraph): ProceduralNode[] {
47
+ const nodes = new Map<string, ProceduralNode>();
48
+ for (const node of graph.nodes) {
49
+ if (!node.id || nodes.has(node.id))
50
+ throw new Error('Procedural graph: duplicate or empty node ID.');
51
+ nodes.set(node.id, node);
52
+ }
53
+ const dependencies = new Map<string, Set<string>>();
54
+ const dependents = new Map<string, string[]>();
55
+ for (const node of graph.nodes) {
56
+ const upstream = new Set<string>();
57
+ for (const input of Object.values(node.inputs)) {
58
+ if (!input.connection) continue;
59
+ if (Object.hasOwn(input, 'value'))
60
+ throw new Error('Procedural graph: connected input also has a value.');
61
+ const source = resolveOutput(input.connection);
62
+ if (source.outputs[input.connection.output] !== input.type) {
63
+ throw new Error('Procedural graph: incompatible connection types.');
64
+ }
65
+ upstream.add(source.id);
66
+ }
67
+ dependencies.set(node.id, upstream);
68
+ for (const identifier of upstream) {
69
+ const downstream = dependents.get(identifier) || [];
70
+ downstream.push(node.id);
71
+ dependents.set(identifier, downstream);
72
+ }
73
+ }
74
+ for (const output of Object.values(graph.outputs)) resolveOutput(output);
75
+ const ordered = graph.nodes.filter(node => dependencies.get(node.id)!.size === 0);
76
+ for (let index = 0; index < ordered.length; index++) {
77
+ for (const identifier of dependents.get(ordered[index].id) || []) {
78
+ const upstream = dependencies.get(identifier)!;
79
+ upstream.delete(ordered[index].id);
80
+ if (!upstream.size) ordered.push(nodes.get(identifier)!);
81
+ }
82
+ }
83
+ if (ordered.length !== graph.nodes.length) throw new Error('Procedural graph: cycle detected.');
84
+ return ordered;
85
+
86
+ /** Resolves an explicitly named output without accepting inherited properties. */
87
+ function resolveOutput(connection: ProceduralConnection): ProceduralNode {
88
+ const node = nodes.get(connection.node);
89
+ if (!node || !Object.hasOwn(node.outputs, connection.output)) {
90
+ throw new Error('Procedural graph: missing node or output.');
91
+ }
92
+ return node;
93
+ }
94
+ }
@@ -0,0 +1,24 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ import type {MaterialXDocument} from './materialx/parse-materialx';
4
+
5
+ /** Loads the parser-bearing MaterialX implementation. */
6
+ async function preload() {
7
+ const {MaterialXLoaderWithParser} = await import('@loaders.gl/scene/materialx-loader');
8
+ return MaterialXLoaderWithParser;
9
+ }
10
+
11
+ /** Metadata-only loader for MaterialX XML documents. */
12
+ export const MaterialXLoader = {
13
+ name: 'MaterialX',
14
+ id: 'materialx',
15
+ module: 'scene',
16
+ version: 'latest',
17
+ extensions: ['mtlx'],
18
+ mimeTypes: ['application/xml'],
19
+ text: true,
20
+ dataType: null as unknown as MaterialXDocument,
21
+ batchType: null as never,
22
+ options: {},
23
+ preload
24
+ } as const;