@luma.gl/gltf 9.3.0-alpha.4 → 9.3.0-alpha.6
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.
- package/dist/dist.dev.js +397 -220
- package/dist/dist.min.js +98 -46
- package/dist/gltf/animations/animations.d.ts +16 -4
- package/dist/gltf/animations/animations.d.ts.map +1 -1
- package/dist/gltf/animations/interpolate.d.ts +4 -3
- package/dist/gltf/animations/interpolate.d.ts.map +1 -1
- package/dist/gltf/animations/interpolate.js +27 -36
- package/dist/gltf/animations/interpolate.js.map +1 -1
- package/dist/gltf/create-gltf-model.d.ts +6 -0
- package/dist/gltf/create-gltf-model.d.ts.map +1 -1
- package/dist/gltf/create-gltf-model.js +96 -44
- package/dist/gltf/create-gltf-model.js.map +1 -1
- package/dist/gltf/create-scenegraph-from-gltf.d.ts +15 -1
- package/dist/gltf/create-scenegraph-from-gltf.d.ts.map +1 -1
- package/dist/gltf/create-scenegraph-from-gltf.js +12 -6
- package/dist/gltf/create-scenegraph-from-gltf.js.map +1 -1
- package/dist/gltf/gltf-animator.d.ts +26 -0
- package/dist/gltf/gltf-animator.d.ts.map +1 -1
- package/dist/gltf/gltf-animator.js +22 -19
- package/dist/gltf/gltf-animator.js.map +1 -1
- package/dist/index.cjs +378 -210
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/parsers/parse-gltf-animations.d.ts +1 -0
- package/dist/parsers/parse-gltf-animations.d.ts.map +1 -1
- package/dist/parsers/parse-gltf-animations.js +46 -23
- package/dist/parsers/parse-gltf-animations.js.map +1 -1
- package/dist/parsers/parse-gltf-lights.d.ts.map +1 -1
- package/dist/parsers/parse-gltf-lights.js +40 -12
- package/dist/parsers/parse-gltf-lights.js.map +1 -1
- package/dist/parsers/parse-gltf.d.ts +16 -1
- package/dist/parsers/parse-gltf.d.ts.map +1 -1
- package/dist/parsers/parse-gltf.js +65 -57
- package/dist/parsers/parse-gltf.js.map +1 -1
- package/dist/parsers/parse-pbr-material.d.ts +46 -1
- package/dist/parsers/parse-pbr-material.d.ts.map +1 -1
- package/dist/parsers/parse-pbr-material.js +137 -13
- package/dist/parsers/parse-pbr-material.js.map +1 -1
- package/dist/pbr/pbr-environment.d.ts +6 -0
- package/dist/pbr/pbr-environment.d.ts.map +1 -1
- package/dist/pbr/pbr-environment.js +1 -0
- package/dist/pbr/pbr-environment.js.map +1 -1
- package/dist/pbr/pbr-material.d.ts +5 -0
- package/dist/pbr/pbr-material.d.ts.map +1 -1
- package/dist/webgl-to-webgpu/convert-webgl-attribute.d.ts +12 -1
- package/dist/webgl-to-webgpu/convert-webgl-attribute.d.ts.map +1 -1
- package/dist/webgl-to-webgpu/convert-webgl-attribute.js +3 -0
- package/dist/webgl-to-webgpu/convert-webgl-attribute.js.map +1 -1
- package/dist/webgl-to-webgpu/convert-webgl-sampler.d.ts +6 -0
- package/dist/webgl-to-webgpu/convert-webgl-sampler.d.ts.map +1 -1
- package/dist/webgl-to-webgpu/convert-webgl-sampler.js +4 -0
- package/dist/webgl-to-webgpu/convert-webgl-sampler.js.map +1 -1
- package/dist/webgl-to-webgpu/convert-webgl-topology.d.ts +2 -0
- package/dist/webgl-to-webgpu/convert-webgl-topology.d.ts.map +1 -1
- package/dist/webgl-to-webgpu/convert-webgl-topology.js +2 -0
- package/dist/webgl-to-webgpu/convert-webgl-topology.js.map +1 -1
- package/package.json +5 -5
- package/src/gltf/animations/animations.ts +17 -5
- package/src/gltf/animations/interpolate.ts +49 -68
- package/src/gltf/create-gltf-model.ts +101 -43
- package/src/gltf/create-scenegraph-from-gltf.ts +39 -11
- package/src/gltf/gltf-animator.ts +34 -25
- package/src/index.ts +1 -2
- package/src/parsers/parse-gltf-animations.ts +63 -26
- package/src/parsers/parse-gltf-lights.ts +51 -13
- package/src/parsers/parse-gltf.ts +90 -77
- package/src/parsers/parse-pbr-material.ts +204 -14
- package/src/pbr/pbr-environment.ts +10 -0
- package/src/pbr/pbr-material.ts +5 -0
- package/src/webgl-to-webgpu/convert-webgl-attribute.ts +12 -1
- package/src/webgl-to-webgpu/convert-webgl-sampler.ts +9 -0
- package/src/webgl-to-webgpu/convert-webgl-topology.ts +2 -0
- package/dist/utils/deep-copy.d.ts +0 -3
- package/dist/utils/deep-copy.d.ts.map +0 -1
- package/dist/utils/deep-copy.js +0 -21
- package/dist/utils/deep-copy.js.map +0 -1
- package/src/utils/deep-copy.ts +0 -22
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import type {Device,
|
|
5
|
+
import type {Device, SamplerProps, TextureFormat, TypedArray} from '@luma.gl/core';
|
|
6
|
+
import {Texture, log, textureFormatDecoder} from '@luma.gl/core';
|
|
6
7
|
import type {GLTFSampler} from '@loaders.gl/gltf';
|
|
7
8
|
import {GL} from '@luma.gl/constants';
|
|
8
9
|
|
|
9
|
-
import {log} from '@luma.gl/core';
|
|
10
10
|
import {type ParsedPBRMaterial} from '../pbr/pbr-material';
|
|
11
11
|
import {type PBREnvironment} from '../pbr/pbr-environment';
|
|
12
12
|
import {type PBRMaterialBindings} from '@luma.gl/shadertools';
|
|
@@ -107,6 +107,7 @@ export function parsePBRMaterial(
|
|
|
107
107
|
if (attributes['NORMAL']) parsedMaterial.defines['HAS_NORMALS'] = true;
|
|
108
108
|
if (attributes['TANGENT'] && options?.useTangents) parsedMaterial.defines['HAS_TANGENTS'] = true;
|
|
109
109
|
if (attributes['TEXCOORD_0']) parsedMaterial.defines['HAS_UV'] = true;
|
|
110
|
+
if (attributes['JOINTS_0'] && attributes['WEIGHTS_0']) parsedMaterial.defines['HAS_SKIN'] = true;
|
|
110
111
|
if (attributes['COLOR_0']) parsedMaterial.defines['HAS_COLORS'] = true;
|
|
111
112
|
|
|
112
113
|
if (options?.imageBasedLightingEnvironment) parsedMaterial.defines['USE_IBL'] = true;
|
|
@@ -239,14 +240,6 @@ function addTexture(
|
|
|
239
240
|
parsedMaterial: ParsedPBRMaterial
|
|
240
241
|
): void {
|
|
241
242
|
const image = gltfTexture.texture.source.image;
|
|
242
|
-
let textureOptions;
|
|
243
|
-
|
|
244
|
-
if (image.compressed) {
|
|
245
|
-
textureOptions = image;
|
|
246
|
-
} else {
|
|
247
|
-
// Texture2D accepts a promise that returns an image as data (Async Textures)
|
|
248
|
-
textureOptions = {data: image};
|
|
249
|
-
}
|
|
250
243
|
|
|
251
244
|
const gltfSampler = {
|
|
252
245
|
wrapS: 10497, // default REPEAT S (U) wrapping mode.
|
|
@@ -256,17 +249,214 @@ function addTexture(
|
|
|
256
249
|
...gltfTexture?.texture?.sampler
|
|
257
250
|
} as GLTFSampler;
|
|
258
251
|
|
|
259
|
-
const
|
|
252
|
+
const baseOptions = {
|
|
260
253
|
id: gltfTexture.uniformName || gltfTexture.id,
|
|
261
|
-
sampler: convertSampler(gltfSampler)
|
|
262
|
-
|
|
263
|
-
|
|
254
|
+
sampler: convertSampler(gltfSampler)
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
let texture: Texture;
|
|
258
|
+
|
|
259
|
+
if (image.compressed) {
|
|
260
|
+
texture = createCompressedTexture(device, image, baseOptions);
|
|
261
|
+
} else {
|
|
262
|
+
const {width, height} = device.getExternalImageSize(image);
|
|
263
|
+
texture = device.createTexture({
|
|
264
|
+
...baseOptions,
|
|
265
|
+
width,
|
|
266
|
+
height,
|
|
267
|
+
data: image
|
|
268
|
+
});
|
|
269
|
+
}
|
|
264
270
|
|
|
265
271
|
parsedMaterial.bindings[uniformName] = texture;
|
|
266
272
|
if (define) parsedMaterial.defines[define] = true;
|
|
267
273
|
parsedMaterial.generatedTextures.push(texture);
|
|
268
274
|
}
|
|
269
275
|
|
|
276
|
+
/** One mip level as produced by loaders.gl compressed texture parsers */
|
|
277
|
+
export type CompressedMipLevel = {
|
|
278
|
+
data: TypedArray;
|
|
279
|
+
width: number;
|
|
280
|
+
height: number;
|
|
281
|
+
textureFormat?: TextureFormat;
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Compressed image from current loaders.gl releases.
|
|
286
|
+
* - `mipmaps` is a boolean (true), NOT an array
|
|
287
|
+
* - `data` is an Array of TextureLevel-like objects
|
|
288
|
+
* - Per-level `textureFormat` is already a luma.gl TextureFormat
|
|
289
|
+
* - Top-level `width`/`height` may be undefined
|
|
290
|
+
*/
|
|
291
|
+
export type CompressedImageDataArray = {
|
|
292
|
+
compressed: true;
|
|
293
|
+
mipmaps?: boolean;
|
|
294
|
+
width?: number;
|
|
295
|
+
height?: number;
|
|
296
|
+
data: CompressedMipLevel[];
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Hypothetical future format where `mipmaps` is an actual array.
|
|
301
|
+
* Kept for forward compatibility.
|
|
302
|
+
*/
|
|
303
|
+
export type CompressedImageMipmapArray = {
|
|
304
|
+
compressed: true;
|
|
305
|
+
width?: number;
|
|
306
|
+
height?: number;
|
|
307
|
+
mipmaps: CompressedMipLevel[];
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
/** Union of all known loaders.gl compressed image shapes */
|
|
311
|
+
export type CompressedImage = CompressedImageDataArray | CompressedImageMipmapArray;
|
|
312
|
+
|
|
313
|
+
function createCompressedTextureFallback(
|
|
314
|
+
device: Device,
|
|
315
|
+
baseOptions: {id: string; sampler: SamplerProps}
|
|
316
|
+
): Texture {
|
|
317
|
+
return device.createTexture({
|
|
318
|
+
...baseOptions,
|
|
319
|
+
format: 'rgba8unorm',
|
|
320
|
+
width: 1,
|
|
321
|
+
height: 1,
|
|
322
|
+
mipLevels: 1
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function resolveCompressedTextureFormat(level: CompressedMipLevel): TextureFormat | undefined {
|
|
327
|
+
return level.textureFormat;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Maximum mip levels that can be filled for a compressed texture.
|
|
332
|
+
* texStorage2D allocates level i at (baseW >> i) × (baseH >> i).
|
|
333
|
+
* Compressed formats can't upload data for levels smaller than one block,
|
|
334
|
+
* so we stop before either dimension drops below the block size.
|
|
335
|
+
*/
|
|
336
|
+
function getMaxCompressedMipLevels(
|
|
337
|
+
baseWidth: number,
|
|
338
|
+
baseHeight: number,
|
|
339
|
+
format: TextureFormat
|
|
340
|
+
): number {
|
|
341
|
+
const {blockWidth = 1, blockHeight = 1} = textureFormatDecoder.getInfo(format);
|
|
342
|
+
let count = 1;
|
|
343
|
+
for (let i = 1; ; i++) {
|
|
344
|
+
const w = Math.max(1, baseWidth >> i);
|
|
345
|
+
const h = Math.max(1, baseHeight >> i);
|
|
346
|
+
if (w < blockWidth || h < blockHeight) break;
|
|
347
|
+
count++;
|
|
348
|
+
}
|
|
349
|
+
return count;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Create a texture from compressed image data produced by loaders.gl.
|
|
354
|
+
* Handles current loaders.gl compressed image layouts:
|
|
355
|
+
*
|
|
356
|
+
* current: {compressed, mipmaps: true, data: [{data, width, height, textureFormat}, ...]}
|
|
357
|
+
* forward: {compressed, mipmaps: [{data, width, height, textureFormat}, ...]}
|
|
358
|
+
*/
|
|
359
|
+
export function createCompressedTexture(
|
|
360
|
+
device: Device,
|
|
361
|
+
image: CompressedImage,
|
|
362
|
+
baseOptions: {id: string; sampler: SamplerProps}
|
|
363
|
+
): Texture {
|
|
364
|
+
// Normalize mip levels from all known loaders.gl formats
|
|
365
|
+
let levels: CompressedMipLevel[];
|
|
366
|
+
|
|
367
|
+
if (Array.isArray((image as any).data) && (image as any).data[0]?.data) {
|
|
368
|
+
// loaders.gl current format: image.data is Array of mip-level objects
|
|
369
|
+
levels = (image as CompressedImageDataArray).data;
|
|
370
|
+
} else if ('mipmaps' in image && Array.isArray((image as CompressedImageMipmapArray).mipmaps)) {
|
|
371
|
+
// Hypothetical future format: image.mipmaps is an Array
|
|
372
|
+
levels = (image as CompressedImageMipmapArray).mipmaps;
|
|
373
|
+
} else {
|
|
374
|
+
levels = [];
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (levels.length === 0 || !levels[0]?.data) {
|
|
378
|
+
log.warn(
|
|
379
|
+
'createCompressedTexture: compressed image has no valid mip levels, creating fallback'
|
|
380
|
+
)();
|
|
381
|
+
return createCompressedTextureFallback(device, baseOptions);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const baseLevel = levels[0];
|
|
385
|
+
const baseWidth = baseLevel.width ?? (image as any).width ?? 0;
|
|
386
|
+
const baseHeight = baseLevel.height ?? (image as any).height ?? 0;
|
|
387
|
+
|
|
388
|
+
if (baseWidth <= 0 || baseHeight <= 0) {
|
|
389
|
+
log.warn('createCompressedTexture: base level has invalid dimensions, creating fallback')();
|
|
390
|
+
return createCompressedTextureFallback(device, baseOptions);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const format = resolveCompressedTextureFormat(baseLevel);
|
|
394
|
+
|
|
395
|
+
if (!format) {
|
|
396
|
+
log.warn('createCompressedTexture: compressed image has no textureFormat, creating fallback')();
|
|
397
|
+
return createCompressedTextureFallback(device, baseOptions);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Validate mip levels: truncate chain at first invalid level.
|
|
401
|
+
// Levels must be contiguous, so we stop at the first level that has
|
|
402
|
+
// a format mismatch, missing data, non-positive dimensions, or
|
|
403
|
+
// dimensions that don't match what texStorage2D will allocate.
|
|
404
|
+
//
|
|
405
|
+
// For block-compressed formats (ASTC, BC, ETC2), texStorage2D allocates
|
|
406
|
+
// mip levels down to 1×1 texels, but compressed data can't be smaller
|
|
407
|
+
// than one block (e.g. 4×4 for ASTC-4x4). Cap the chain so we never
|
|
408
|
+
// try to upload data whose block-aligned size exceeds the allocated level.
|
|
409
|
+
const maxMipLevels = getMaxCompressedMipLevels(baseWidth, baseHeight, format);
|
|
410
|
+
const levelLimit = Math.min(levels.length, maxMipLevels);
|
|
411
|
+
|
|
412
|
+
let validLevelCount = 1;
|
|
413
|
+
for (let i = 1; i < levelLimit; i++) {
|
|
414
|
+
const level = levels[i];
|
|
415
|
+
if (!level.data || level.width <= 0 || level.height <= 0) {
|
|
416
|
+
log.warn(`createCompressedTexture: mip level ${i} has invalid data/dimensions, truncating`)();
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
const levelFormat = resolveCompressedTextureFormat(level);
|
|
420
|
+
if (levelFormat && levelFormat !== format) {
|
|
421
|
+
log.warn(
|
|
422
|
+
`createCompressedTexture: mip level ${i} format '${levelFormat}' differs from base '${format}', truncating`
|
|
423
|
+
)();
|
|
424
|
+
break;
|
|
425
|
+
}
|
|
426
|
+
const expectedW = Math.max(1, baseWidth >> i);
|
|
427
|
+
const expectedH = Math.max(1, baseHeight >> i);
|
|
428
|
+
if (level.width !== expectedW || level.height !== expectedH) {
|
|
429
|
+
log.warn(
|
|
430
|
+
`createCompressedTexture: mip level ${i} dimensions ${level.width}x${level.height} ` +
|
|
431
|
+
`don't match expected ${expectedW}x${expectedH}, truncating`
|
|
432
|
+
)();
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
435
|
+
validLevelCount++;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const texture = device.createTexture({
|
|
439
|
+
...baseOptions,
|
|
440
|
+
format,
|
|
441
|
+
usage: Texture.TEXTURE | Texture.COPY_DST,
|
|
442
|
+
width: baseWidth,
|
|
443
|
+
height: baseHeight,
|
|
444
|
+
mipLevels: validLevelCount,
|
|
445
|
+
data: baseLevel.data
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// Upload additional validated mip levels
|
|
449
|
+
for (let i = 1; i < validLevelCount; i++) {
|
|
450
|
+
texture.writeData(levels[i].data, {
|
|
451
|
+
width: levels[i].width,
|
|
452
|
+
height: levels[i].height,
|
|
453
|
+
mipLevel: i
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return texture;
|
|
458
|
+
}
|
|
459
|
+
|
|
270
460
|
/*
|
|
271
461
|
/**
|
|
272
462
|
* Parses a GLTF material definition into uniforms and parameters for the PBR shader module
|
|
@@ -10,13 +10,19 @@ import {loadImageTexture} from '@loaders.gl/textures';
|
|
|
10
10
|
export type PBREnvironment = {
|
|
11
11
|
/** Bi-directional Reflectance Distribution Function (BRDF) lookup table */
|
|
12
12
|
brdfLutTexture: DynamicTexture;
|
|
13
|
+
/** Diffuse irradiance cubemap. */
|
|
13
14
|
diffuseEnvSampler: DynamicTexture;
|
|
15
|
+
/** Specular reflection cubemap with mip chain. */
|
|
14
16
|
specularEnvSampler: DynamicTexture;
|
|
15
17
|
};
|
|
16
18
|
|
|
19
|
+
/** Configuration used to load an image-based lighting environment. */
|
|
17
20
|
export type PBREnvironmentProps = {
|
|
21
|
+
/** URL of the BRDF lookup texture. */
|
|
18
22
|
brdfLutUrl: string;
|
|
23
|
+
/** Callback that returns the URL for a diffuse or specular cubemap face and mip level. */
|
|
19
24
|
getTexUrl: (name: string, dir: number, level: number) => string;
|
|
25
|
+
/** Number of mip levels in the specular environment map. */
|
|
20
26
|
specularMipLevels?: number;
|
|
21
27
|
};
|
|
22
28
|
|
|
@@ -73,6 +79,7 @@ export function loadPBREnvironment(device: Device, props: PBREnvironmentProps):
|
|
|
73
79
|
// TODO put somewhere common
|
|
74
80
|
const FACES = [0, 1, 2, 3, 4, 5];
|
|
75
81
|
|
|
82
|
+
/** Construction props for an asynchronously loaded cubemap. */
|
|
76
83
|
function makeCube(
|
|
77
84
|
device: Device,
|
|
78
85
|
{
|
|
@@ -80,8 +87,11 @@ function makeCube(
|
|
|
80
87
|
getTextureForFace,
|
|
81
88
|
sampler
|
|
82
89
|
}: {
|
|
90
|
+
/** Debug id assigned to the created texture. */
|
|
83
91
|
id: string;
|
|
92
|
+
/** Returns the image promise or mip-array promises for one cubemap face. */
|
|
84
93
|
getTextureForFace: (dir: number) => Promise<any> | Promise<any>[];
|
|
94
|
+
/** Sampler configuration shared across faces. */
|
|
85
95
|
sampler: SamplerProps;
|
|
86
96
|
}
|
|
87
97
|
): DynamicTexture {
|
package/src/pbr/pbr-material.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import type {Texture, Parameters} from '@luma.gl/core';
|
|
2
2
|
import {PBRMaterialBindings, PBRMaterialUniforms, PBRProjectionProps} from '@luma.gl/shadertools';
|
|
3
3
|
|
|
4
|
+
/** Material state extracted from a glTF primitive for consumption by the PBR shader module. */
|
|
4
5
|
export type ParsedPBRMaterial = {
|
|
6
|
+
/** Shader defines inferred from geometry and material features. */
|
|
5
7
|
readonly defines: Record<string, boolean>;
|
|
8
|
+
/** Texture and sampler bindings for the PBR shader module. */
|
|
6
9
|
readonly bindings: Partial<PBRMaterialBindings>;
|
|
10
|
+
/** Uniform values for the projection and PBR shader modules. */
|
|
7
11
|
readonly uniforms: Partial<PBRProjectionProps & PBRMaterialUniforms>;
|
|
12
|
+
/** Render pipeline parameters derived from the glTF material. */
|
|
8
13
|
readonly parameters: Parameters;
|
|
9
14
|
/** @deprecated Use parameters */
|
|
10
15
|
readonly glParameters: Record<string, any>;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// TODO: convert in loaders.gl?
|
|
6
6
|
import type {TypedArray} from '@math.gl/types';
|
|
7
7
|
|
|
8
|
+
/** Maps glTF accessor type strings to their component counts. */
|
|
8
9
|
export const ATTRIBUTE_TYPE_TO_COMPONENTS: Record<string, number> = {
|
|
9
10
|
SCALAR: 1,
|
|
10
11
|
VEC2: 2,
|
|
@@ -15,6 +16,7 @@ export const ATTRIBUTE_TYPE_TO_COMPONENTS: Record<string, number> = {
|
|
|
15
16
|
MAT4: 16
|
|
16
17
|
};
|
|
17
18
|
|
|
19
|
+
/** Maps glTF accessor component-type enums to typed-array constructors. */
|
|
18
20
|
export const ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY: Record<number, any> = {
|
|
19
21
|
5120: Int8Array,
|
|
20
22
|
5121: Uint8Array,
|
|
@@ -24,16 +26,25 @@ export const ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY: Record<number, any> = {
|
|
|
24
26
|
5126: Float32Array
|
|
25
27
|
};
|
|
26
28
|
|
|
29
|
+
/** Minimal accessor shape required to materialize a typed array. */
|
|
27
30
|
type GLTFAccessor = {
|
|
31
|
+
/** Numeric component type enum. */
|
|
28
32
|
componentType: number;
|
|
33
|
+
/** Accessor type string such as `VEC3` or `SCALAR`. */
|
|
29
34
|
type: string;
|
|
35
|
+
/** Number of logical elements in the accessor. */
|
|
30
36
|
count: number;
|
|
31
|
-
|
|
37
|
+
/** Buffer view carrying the raw bytes. */
|
|
38
|
+
bufferView?: {data: {buffer: ArrayBufferLike; byteOffset?: number}};
|
|
39
|
+
/** Byte offset into the buffer view. */
|
|
32
40
|
byteOffset?: number;
|
|
33
41
|
};
|
|
34
42
|
|
|
43
|
+
/** Converts a glTF accessor into a typed array plus its component count. */
|
|
35
44
|
export function accessorToTypedArray(accessor: GLTFAccessor): {
|
|
45
|
+
/** Typed array view over the accessor data. */
|
|
36
46
|
typedArray: TypedArray;
|
|
47
|
+
/** Number of scalar components per element. */
|
|
37
48
|
components: number;
|
|
38
49
|
} {
|
|
39
50
|
const ArrayType = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[accessor.componentType];
|
|
@@ -7,10 +7,15 @@
|
|
|
7
7
|
import type {SamplerProps} from '@luma.gl/core';
|
|
8
8
|
import {GL} from '@luma.gl/constants';
|
|
9
9
|
|
|
10
|
+
/** Minimal glTF sampler representation used during conversion. */
|
|
10
11
|
type GLTFSampler = {
|
|
12
|
+
/** Horizontal wrap mode. */
|
|
11
13
|
wrapS?: GL.CLAMP_TO_EDGE | GL.REPEAT | GL.MIRRORED_REPEAT;
|
|
14
|
+
/** Vertical wrap mode. */
|
|
12
15
|
wrapT?: GL.CLAMP_TO_EDGE | GL.REPEAT | GL.MIRRORED_REPEAT;
|
|
16
|
+
/** Magnification filter. */
|
|
13
17
|
magFilter?: GL.NEAREST | GL.LINEAR;
|
|
18
|
+
/** Minification and mip filter combination. */
|
|
14
19
|
minFilter?:
|
|
15
20
|
| GL.NEAREST
|
|
16
21
|
| GL.LINEAR
|
|
@@ -20,6 +25,7 @@ type GLTFSampler = {
|
|
|
20
25
|
| GL.LINEAR_MIPMAP_LINEAR;
|
|
21
26
|
};
|
|
22
27
|
|
|
28
|
+
/** Converts a glTF sampler into luma.gl sampler props. */
|
|
23
29
|
export function convertSampler(gltfSampler: GLTFSampler): SamplerProps {
|
|
24
30
|
return {
|
|
25
31
|
addressModeU: convertSamplerWrapMode(gltfSampler.wrapS),
|
|
@@ -29,6 +35,7 @@ export function convertSampler(gltfSampler: GLTFSampler): SamplerProps {
|
|
|
29
35
|
};
|
|
30
36
|
}
|
|
31
37
|
|
|
38
|
+
/** Converts a glTF wrap enum into a luma.gl address mode. */
|
|
32
39
|
function convertSamplerWrapMode(
|
|
33
40
|
mode: GL.CLAMP_TO_EDGE | GL.REPEAT | GL.MIRRORED_REPEAT | undefined
|
|
34
41
|
): 'clamp-to-edge' | 'repeat' | 'mirror-repeat' | undefined {
|
|
@@ -44,6 +51,7 @@ function convertSamplerWrapMode(
|
|
|
44
51
|
}
|
|
45
52
|
}
|
|
46
53
|
|
|
54
|
+
/** Converts a glTF mag filter enum into a luma.gl mag filter. */
|
|
47
55
|
function convertSamplerMagFilter(
|
|
48
56
|
mode: GL.NEAREST | GL.LINEAR | undefined
|
|
49
57
|
): 'nearest' | 'linear' | undefined {
|
|
@@ -57,6 +65,7 @@ function convertSamplerMagFilter(
|
|
|
57
65
|
}
|
|
58
66
|
}
|
|
59
67
|
|
|
68
|
+
/** Converts a glTF min filter enum into luma.gl minification and mipmap filters. */
|
|
60
69
|
function convertSamplerMinFilter(
|
|
61
70
|
mode:
|
|
62
71
|
| GL.NEAREST
|
|
@@ -8,6 +8,7 @@ import {PrimitiveTopology} from '@luma.gl/core';
|
|
|
8
8
|
// `@luma.gl/constants`. Locally we use `GLEnum` instead of `GL` to avoid
|
|
9
9
|
// conflicts with the `babel-plugin-inline-webgl-constants` plugin.
|
|
10
10
|
// eslint-disable-next-line no-shadow
|
|
11
|
+
/** Minimal WebGL draw-mode enum subset used by the glTF converter. */
|
|
11
12
|
export enum GLEnum {
|
|
12
13
|
POINTS = 0x0,
|
|
13
14
|
LINES = 0x1,
|
|
@@ -18,6 +19,7 @@ export enum GLEnum {
|
|
|
18
19
|
TRIANGLE_FAN = 0x6
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
/** Converts a WebGL draw mode into a luma.gl primitive topology string. */
|
|
21
23
|
export function convertGLDrawModeToTopology(
|
|
22
24
|
drawMode:
|
|
23
25
|
| GLEnum.POINTS
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"deep-copy.d.ts","sourceRoot":"","sources":["../../src/utils/deep-copy.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,wBAAgB,QAAQ,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAoBzC"}
|
package/dist/utils/deep-copy.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/** Deeply copies a JS data structure */
|
|
2
|
-
export function deepCopy(object) {
|
|
3
|
-
// don't copy binary data
|
|
4
|
-
if (ArrayBuffer.isView(object) ||
|
|
5
|
-
object instanceof ArrayBuffer ||
|
|
6
|
-
object instanceof ImageBitmap) {
|
|
7
|
-
return object;
|
|
8
|
-
}
|
|
9
|
-
if (Array.isArray(object)) {
|
|
10
|
-
return object.map(deepCopy);
|
|
11
|
-
}
|
|
12
|
-
if (object && typeof object === 'object') {
|
|
13
|
-
const result = {};
|
|
14
|
-
for (const key in object) {
|
|
15
|
-
result[key] = deepCopy(object[key]);
|
|
16
|
-
}
|
|
17
|
-
return result;
|
|
18
|
-
}
|
|
19
|
-
return object;
|
|
20
|
-
}
|
|
21
|
-
//# sourceMappingURL=deep-copy.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"deep-copy.js","sourceRoot":"","sources":["../../src/utils/deep-copy.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,MAAM,UAAU,QAAQ,CAAC,MAAW;IAClC,yBAAyB;IACzB,IACE,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC;QAC1B,MAAM,YAAY,WAAW;QAC7B,MAAM,YAAY,WAAW,EAC7B,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QACzC,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;YACzB,MAAM,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACtC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/src/utils/deep-copy.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/** Deeply copies a JS data structure */
|
|
2
|
-
export function deepCopy(object: any): any {
|
|
3
|
-
// don't copy binary data
|
|
4
|
-
if (
|
|
5
|
-
ArrayBuffer.isView(object) ||
|
|
6
|
-
object instanceof ArrayBuffer ||
|
|
7
|
-
object instanceof ImageBitmap
|
|
8
|
-
) {
|
|
9
|
-
return object;
|
|
10
|
-
}
|
|
11
|
-
if (Array.isArray(object)) {
|
|
12
|
-
return object.map(deepCopy);
|
|
13
|
-
}
|
|
14
|
-
if (object && typeof object === 'object') {
|
|
15
|
-
const result: typeof object = {};
|
|
16
|
-
for (const key in object) {
|
|
17
|
-
result[key] = deepCopy(object[key]);
|
|
18
|
-
}
|
|
19
|
-
return result;
|
|
20
|
-
}
|
|
21
|
-
return object;
|
|
22
|
-
}
|