@gltf-transform/core
Advanced tools
Comparing version 0.11.0-alpha.1 to 0.11.0
@@ -124,1 +124,5 @@ /** | ||
} | ||
export declare enum Format { | ||
GLTF = "GLTF", | ||
GLB = "GLB" | ||
} |
@@ -0,1 +1,2 @@ | ||
/** @module core */ | ||
export { Document, Transform } from './document'; | ||
@@ -8,3 +9,3 @@ export { JSONDocument } from './json-document'; | ||
export { BufferUtils, ColorUtils, FileUtils, ImageUtils, ImageUtilsFormat, Logger, MathUtils, uuid } from './utils/'; | ||
export { TypedArray, TypedArrayConstructor, PropertyType, TextureChannel, VertexLayout, vec2, vec3, vec4, mat3, mat4, GLB_BUFFER } from './constants'; | ||
export { TypedArray, TypedArrayConstructor, PropertyType, Format, TextureChannel, VertexLayout, vec2, vec3, vec4, mat3, mat4, GLB_BUFFER } from './constants'; | ||
export { GLTF } from './types/gltf'; |
@@ -23,3 +23,3 @@ import { Extension } from './extension'; | ||
* import { Document } from '@gltf-transform/core'; | ||
* import { dedup } from '@gltf-transform/lib'; | ||
* import { dedup } from '@gltf-transform/functions'; | ||
* | ||
@@ -26,0 +26,0 @@ * const doc = new Document(); |
@@ -44,3 +44,4 @@ import { PropertyType } from './constants'; | ||
/** Dependency IDs needed by this extension, to be installed before I/O. */ | ||
readonly dependencies: string[]; | ||
readonly readDependencies: string[]; | ||
readonly writeDependencies: string[]; | ||
protected required: boolean; | ||
@@ -47,0 +48,0 @@ protected properties: Set<ExtensionProperty>; |
@@ -46,3 +46,3 @@ import { VertexLayout } from '../constants'; | ||
/** Converts a {@link Document} to glTF-formatted JSON and a resource map. */ | ||
writeJSON(doc: Document, options: WriterOptions): JSONDocument; | ||
writeJSON(doc: Document, _options?: Partial<WriterOptions>): JSONDocument; | ||
/********************************************************************************************** | ||
@@ -49,0 +49,0 @@ * Binary -> JSON. |
@@ -14,4 +14,4 @@ import { Document } from '../document'; | ||
export declare class GLTFReader { | ||
static read(jsonDoc: JSONDocument, options?: ReaderOptions): Document; | ||
static read(jsonDoc: JSONDocument, _options?: ReaderOptions): Document; | ||
private static validate; | ||
} |
@@ -0,1 +1,2 @@ | ||
import { Document } from '../document'; | ||
import { JSONDocument } from '../json-document'; | ||
@@ -15,3 +16,3 @@ import { Accessor, Buffer, Camera, Material, Mesh, Node, Property, Skin, Texture, TextureInfo } from '../properties'; | ||
readonly jsonDoc: JSONDocument; | ||
readonly options: WriterOptions; | ||
readonly options: Required<WriterOptions>; | ||
readonly accessorIndexMap: Map<Accessor, number>; | ||
@@ -30,3 +31,5 @@ readonly cameraIndexMap: Map<Camera, number>; | ||
readonly otherBufferViewsIndexMap: Map<ArrayBuffer, number>; | ||
readonly extensionData: {}; | ||
readonly extensionData: { | ||
[key: string]: unknown; | ||
}; | ||
bufferURIGenerator: UniqueURIGenerator; | ||
@@ -37,3 +40,3 @@ imageURIGenerator: UniqueURIGenerator; | ||
readonly accessorUsageGroupedByParent: Set<string>; | ||
constructor(jsonDoc: JSONDocument, options: WriterOptions); | ||
constructor(doc: Document, jsonDoc: JSONDocument, options: Required<WriterOptions>); | ||
/** | ||
@@ -52,3 +55,3 @@ * Creates a TextureInfo definition, and any Texture or Sampler definitions it requires. If | ||
*/ | ||
getAccessorUsage(accessor: Accessor): string; | ||
getAccessorUsage(accessor: Accessor): string | null; | ||
/** | ||
@@ -55,0 +58,0 @@ * Sets usage for the given accessor. Some accessor types must be grouped into |
@@ -1,2 +0,2 @@ | ||
import { VertexLayout } from '../constants'; | ||
import { Format, VertexLayout } from '../constants'; | ||
import { Document } from '../document'; | ||
@@ -6,5 +6,5 @@ import { JSONDocument } from '../json-document'; | ||
export interface WriterOptions { | ||
format: Format; | ||
logger?: Logger; | ||
basename?: string; | ||
isGLB?: boolean; | ||
vertexLayout?: VertexLayout; | ||
@@ -17,3 +17,3 @@ dependencies?: { | ||
export declare class GLTFWriter { | ||
static write(doc: Document, options?: WriterOptions): JSONDocument; | ||
static write(doc: Document, options: Required<WriterOptions>): JSONDocument; | ||
} |
@@ -191,3 +191,3 @@ import { PropertyType, TypedArray } from '../constants'; | ||
/** Assigns the {@link Buffer} into which this accessor will be organized. */ | ||
setBuffer(buffer: Buffer): this; | ||
setBuffer(buffer: Buffer | null): this; | ||
/** Returns the raw typed array underlying this accessor. */ | ||
@@ -194,0 +194,0 @@ getArray(): TypedArray | null; |
@@ -62,3 +62,3 @@ import { PropertyType } from '../constants'; | ||
/** Target {@link Node} animated by the channel. */ | ||
setTargetNode(targetNode: Node): this; | ||
setTargetNode(targetNode: Node | null): this; | ||
/** | ||
@@ -73,3 +73,3 @@ * Keyframe data input/output values for the channel. Must be attached to the same | ||
*/ | ||
setSampler(sampler: AnimationSampler): this; | ||
setSampler(sampler: AnimationSampler | null): this; | ||
} |
@@ -31,2 +31,3 @@ import { ExtensibleProperty } from './extensible-property'; | ||
abstract readonly parentTypes: string[]; | ||
/** @hidden */ | ||
constructor(graph: PropertyGraph, _extension: ExtensionPropertyParent); | ||
@@ -33,0 +34,0 @@ dispose(): void; |
@@ -19,3 +19,3 @@ import { PropertyType } from '../constants'; | ||
* behavior is necessary (like raycasting or collisions) prefer to assign each primitive to a | ||
* different mesh. The number of GPU draw calls is typically not unaffected by grouping or | ||
* different mesh. The number of GPU draw calls is typically not affected by grouping or | ||
* ungrouping primitives to a mesh. | ||
@@ -22,0 +22,0 @@ * |
@@ -52,2 +52,3 @@ import { PropertyType } from '../constants'; | ||
private readonly _extensions; | ||
private defaultScene; | ||
private accessors; | ||
@@ -96,2 +97,6 @@ private animations; | ||
listScenes(): Scene[]; | ||
/** Default {@link Scene} associated with this root. */ | ||
setDefaultScene(defaultScene: Scene | null): this; | ||
/** Default {@link Scene} associated with this root. */ | ||
getDefaultScene(): Scene | null; | ||
/********************************************************************************************** | ||
@@ -98,0 +103,0 @@ * Nodes. |
import { vec2 } from '../constants'; | ||
export interface ImageUtilsFormat { | ||
getSize(buffer: ArrayBuffer): vec2; | ||
getChannels(buffer: ArrayBuffer): number; | ||
getGPUByteLength?(buffer: ArrayBuffer): number; | ||
getSize(buffer: ArrayBuffer): vec2 | null; | ||
getChannels(buffer: ArrayBuffer): number | null; | ||
getGPUByteLength?(buffer: ArrayBuffer): number | null; | ||
} | ||
@@ -19,3 +19,3 @@ /** | ||
/** Returns the dimensions of the image. */ | ||
static getSize(buffer: ArrayBuffer, mimeType: string): vec2; | ||
static getSize(buffer: ArrayBuffer, mimeType: string): vec2 | null; | ||
/** | ||
@@ -26,5 +26,5 @@ * Returns a conservative estimate of the number of channels in the image. For some image | ||
*/ | ||
static getChannels(buffer: ArrayBuffer, mimeType: string): number; | ||
static getChannels(buffer: ArrayBuffer, mimeType: string): number | null; | ||
/** Returns a conservative estimate of the GPU memory required by this image. */ | ||
static getMemSize(buffer: ArrayBuffer, mimeType: string): number; | ||
static getMemSize(buffer: ArrayBuffer, mimeType: string): number | null; | ||
/** Returns the preferred file extension for the given MIME type. */ | ||
@@ -31,0 +31,0 @@ static mimeTypeToExtension(mimeType: string): string; |
@@ -5,5 +5,4 @@ export * from './buffer-utils'; | ||
export * from './image-utils'; | ||
export * from './graph-utils'; | ||
export * from './math-utils'; | ||
export * from './logger'; | ||
export * from './uuid'; |
{ | ||
"name": "@gltf-transform/core", | ||
"version": "0.11.0-alpha.1", | ||
"version": "0.11.0", | ||
"repository": "github:donmccurdy/glTF-Transform", | ||
@@ -42,3 +42,3 @@ "description": "glTF 2.0 SDK for JavaScript, TypeScript, and Node.js", | ||
}, | ||
"gitHead": "29984ac49e9435ecff2fc4ba5350803c4c5efa31" | ||
"gitHead": "129a889c1e406fbd8904a49dae667c34fc55e98f" | ||
} |
@@ -123,1 +123,6 @@ // Injected at compile time, from $npm_package_version. | ||
} | ||
export enum Format { | ||
GLTF = 'GLTF', | ||
GLB = 'GLB', | ||
} |
@@ -1,2 +0,2 @@ | ||
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-namespace */ | ||
/** @module core */ | ||
@@ -10,36 +10,3 @@ export { Document, Transform } from './document'; | ||
export { BufferUtils, ColorUtils, FileUtils, ImageUtils, ImageUtilsFormat, Logger, MathUtils, uuid } from './utils/'; | ||
export { TypedArray, TypedArrayConstructor, PropertyType, TextureChannel, VertexLayout, vec2, vec3, vec4, mat3, mat4, GLB_BUFFER } from './constants'; | ||
export { TypedArray, TypedArrayConstructor, PropertyType, Format, TextureChannel, VertexLayout, vec2, vec3, vec4, mat3, mat4, GLB_BUFFER } from './constants'; | ||
export { GLTF } from './types/gltf'; | ||
/** [[include:CONCEPTS.md]] */ | ||
namespace Concepts {} | ||
/** [[include:LIBRARY.md]] */ | ||
namespace Library {} | ||
/** [[include:EXTENSIONS.md]] */ | ||
namespace Extensions {} | ||
/** [[include:CONTRIBUTING.md]] */ | ||
namespace Contributing {} | ||
/** | ||
* # CLI | ||
* | ||
* For easier access to its library, glTF-Transform offers a command-line interface (CLI). The | ||
* CLI supports many of the features of the `@gltf-transform/lib` package, and some general tools | ||
* for inspecting and packing/unpacking glTF or GLB files. | ||
* | ||
* Installation: | ||
* | ||
* ```shell | ||
* npm install --global @gltf-transform/cli | ||
* ``` | ||
* | ||
* Help output: | ||
* | ||
* ```shell | ||
* [[include:CLI_HELP.md]] | ||
* ``` | ||
*/ | ||
namespace CLI {} |
@@ -26,3 +26,3 @@ import { PropertyType } from './constants'; | ||
* import { Document } from '@gltf-transform/core'; | ||
* import { dedup } from '@gltf-transform/lib'; | ||
* import { dedup } from '@gltf-transform/functions'; | ||
* | ||
@@ -192,4 +192,5 @@ * const doc = new Document(); | ||
createExtension<T extends Extension>(ctor: new (doc: Document) => T): T { | ||
const extensionName = (ctor as unknown as {EXTENSION_NAME: 'string'}).EXTENSION_NAME; | ||
const prevExtension = this.getRoot().listExtensionsUsed() | ||
.find((ext) => ext.extensionName === ctor['EXTENSION_NAME']); | ||
.find((ext) => ext.extensionName === extensionName); | ||
return (prevExtension || new ctor(this)) as T; | ||
@@ -196,0 +197,0 @@ } |
@@ -32,3 +32,3 @@ import { PropertyType } from './constants'; | ||
/** Official name of the extension. */ | ||
public readonly extensionName: string; | ||
public readonly extensionName: string = ''; | ||
/** | ||
@@ -46,3 +46,4 @@ * Before reading, extension should be called for these {@link Property} types. *Most | ||
/** Dependency IDs needed by this extension, to be installed before I/O. */ | ||
public readonly dependencies: string[] = []; | ||
public readonly readDependencies: string[] = []; | ||
public readonly writeDependencies: string[] = []; | ||
@@ -49,0 +50,0 @@ protected required = false; |
@@ -0,1 +1,2 @@ | ||
import { Format } from '../constants'; | ||
import { Document } from '../document'; | ||
@@ -114,3 +115,3 @@ import { JSONDocument } from '../json-document'; | ||
const isGLBBuffer = isGLB && index === images.length; | ||
if (resource['bufferView'] === undefined && !isGLBBuffer) { | ||
if ((resource as GLTF.IImage)['bufferView'] === undefined && !isGLBBuffer) { | ||
throw new Error('Missing resource URI.'); | ||
@@ -138,7 +139,7 @@ } | ||
const {json, resources} = GLTFWriter.write(doc, { | ||
basename: FileUtils.basename(uri), | ||
isGLB: false, | ||
format: Format.GLTF, | ||
logger: this._logger, | ||
dependencies: this._dependencies, | ||
vertexLayout: this._vertexLayout, | ||
basename: FileUtils.basename(uri), | ||
}); | ||
@@ -145,0 +146,0 @@ const {_fs: fs, _path: path} = this; |
@@ -1,2 +0,2 @@ | ||
import { GLB_BUFFER, VertexLayout } from '../constants'; | ||
import { Format, GLB_BUFFER, VertexLayout } from '../constants'; | ||
import { Document } from '../document'; | ||
@@ -10,2 +10,7 @@ import { Extension } from '../extension'; | ||
enum ChunkType { | ||
JSON = 0x4E4F534A, | ||
BIN = 0x004E4942 | ||
} | ||
/** | ||
@@ -75,9 +80,13 @@ * # PlatformIO | ||
/** Converts a {@link Document} to glTF-formatted JSON and a resource map. */ | ||
public writeJSON (doc: Document, options: WriterOptions): JSONDocument { | ||
if (options.isGLB && doc.getRoot().listBuffers().length !== 1) { | ||
throw new Error('GLB must have exactly 1 buffer.'); | ||
public writeJSON (doc: Document, _options: Partial<WriterOptions> = {}): JSONDocument { | ||
if (_options.format === Format.GLB && doc.getRoot().listBuffers().length > 1) { | ||
throw new Error('GLB must have 0–1 buffers.'); | ||
} | ||
options.vertexLayout = this._vertexLayout; | ||
options.dependencies = {...this._dependencies, ...options.dependencies}; | ||
return GLTFWriter.write(doc, options); | ||
return GLTFWriter.write(doc, { | ||
format: _options.format || Format.GLTF, | ||
logger: _options.logger || this._logger, | ||
vertexLayout: _options.vertexLayout || this._vertexLayout, | ||
dependencies: {...this._dependencies, ..._options.dependencies}, | ||
basename: _options.basename || '' | ||
} as Required<WriterOptions>); | ||
} | ||
@@ -115,12 +124,11 @@ | ||
// Decode and verify chunk headers. | ||
// Decode JSON chunk. | ||
const jsonChunkHeader = new Uint32Array(glb, 12, 2); | ||
if (jsonChunkHeader[1] !== ChunkType.JSON) { | ||
throw new Error('Missing required GLB JSON chunk.'); | ||
} | ||
const jsonByteOffset = 20; | ||
const jsonByteLength = jsonChunkHeader[0]; | ||
const binaryChunkHeader = new Uint32Array(glb, jsonByteOffset + jsonByteLength, 2); | ||
if (jsonChunkHeader[1] !== 0x4E4F534A || binaryChunkHeader[1] !== 0x004E4942) { | ||
throw new Error('Unexpected GLB layout.'); | ||
} | ||
// Decode content. | ||
const jsonText = BufferUtils.decodeText( | ||
@@ -130,7 +138,19 @@ glb.slice(jsonByteOffset, jsonByteOffset + jsonByteLength) | ||
const json = JSON.parse(jsonText) as GLTF.IGLTF; | ||
const binaryByteOffset = jsonByteOffset + jsonByteLength + 8; | ||
const binaryByteLength = binaryChunkHeader[0]; | ||
const binary = glb.slice(binaryByteOffset, binaryByteOffset + binaryByteLength); | ||
return {json, resources: {[GLB_BUFFER]: binary}}; | ||
// Decode BIN chunk. | ||
const binByteOffset = jsonByteOffset + jsonByteLength; | ||
if (glb.byteLength <= binByteOffset) { | ||
return {json, resources: {}}; | ||
} | ||
const binChunkHeader = new Uint32Array(glb, binByteOffset, 2); | ||
if (binChunkHeader[1] !== ChunkType.BIN) { | ||
throw new Error('Expected GLB BIN in second chunk.'); | ||
} | ||
const binByteLength = binChunkHeader[0]; | ||
const binBuffer = glb.slice(binByteOffset + 8, binByteOffset + 8 + binByteLength); | ||
return {json, resources: {[GLB_BUFFER]: binBuffer}}; | ||
} | ||
@@ -150,4 +170,4 @@ | ||
const {json, resources} = this.writeJSON(doc, { | ||
format: Format.GLB, | ||
basename: '', | ||
isGLB: true, | ||
logger: this._logger, | ||
@@ -158,2 +178,4 @@ dependencies: this._dependencies, | ||
const header = new Uint32Array([0x46546C67, 2, 12]); | ||
const jsonText = JSON.stringify(json); | ||
@@ -163,14 +185,16 @@ const jsonChunkData = BufferUtils.pad( BufferUtils.encodeText(jsonText), 0x20 ); | ||
const jsonChunk = BufferUtils.concat([jsonChunkHeader, jsonChunkData]); | ||
header[header.length - 1] += jsonChunk.byteLength; | ||
const binaryChunkData | ||
= BufferUtils.pad(Object.values(resources)[0] || new ArrayBuffer(0), 0x00); | ||
const binaryChunkHeader = new Uint32Array([binaryChunkData.byteLength, 0x004E4942]).buffer; | ||
const binaryChunk = BufferUtils.concat([binaryChunkHeader, binaryChunkData]); | ||
const binBuffer = Object.values(resources)[0]; | ||
if (!binBuffer || !binBuffer.byteLength) { | ||
return BufferUtils.concat([header.buffer, jsonChunk]); | ||
} | ||
const header = new Uint32Array([ | ||
0x46546C67, 2, 12 + jsonChunk.byteLength + binaryChunk.byteLength | ||
]).buffer; | ||
const binChunkData = BufferUtils.pad(binBuffer, 0x00); | ||
const binChunkHeader = new Uint32Array([binChunkData.byteLength, 0x004E4942]).buffer; | ||
const binChunk = BufferUtils.concat([binChunkHeader, binChunkData]); | ||
header[header.length - 1] += binChunk.byteLength; | ||
return BufferUtils.concat([header, jsonChunk, binaryChunk]); | ||
return BufferUtils.concat([header.buffer, jsonChunk, binChunk]); | ||
} | ||
} |
@@ -33,7 +33,7 @@ import { JSONDocument } from '../json-document'; | ||
const textureDef = this.jsonDoc.json.textures[textureInfoDef.index]; | ||
const textureDef = this.jsonDoc.json.textures![textureInfoDef.index]; | ||
if (textureDef.sampler === undefined) return; | ||
const samplerDef = this.jsonDoc.json.samplers[textureDef.sampler]; | ||
const samplerDef = this.jsonDoc.json.samplers![textureDef.sampler]; | ||
@@ -40,0 +40,0 @@ if (samplerDef.magFilter !== undefined) { |
@@ -33,3 +33,4 @@ import { GLB_BUFFER, PropertyType, TypedArray, mat4, vec3, vec4 } from '../constants'; | ||
export class GLTFReader { | ||
public static read(jsonDoc: JSONDocument, options: ReaderOptions = DEFAULT_OPTIONS): Document { | ||
public static read(jsonDoc: JSONDocument, _options: ReaderOptions = DEFAULT_OPTIONS): Document { | ||
const options = {...DEFAULT_OPTIONS, ..._options} as Required<ReaderOptions>; | ||
const {json} = jsonDoc; | ||
@@ -64,3 +65,3 @@ const doc = new Document(); | ||
for (const key of extension.dependencies) { | ||
for (const key of extension.readDependencies) { | ||
extension.install(key, options.dependencies[key]); | ||
@@ -98,3 +99,3 @@ } | ||
context.accessors = accessorDefs.map((accessorDef) => { | ||
const buffer = context.bufferViewBuffers[accessorDef.bufferView]; | ||
const buffer = context.bufferViewBuffers[accessorDef.bufferView!]; | ||
const accessor = doc.createAccessor(accessorDef.name, buffer).setType(accessorDef.type); | ||
@@ -141,4 +142,4 @@ | ||
if (imageDef.bufferView !== undefined) { | ||
const bufferViewDef = json.bufferViews[imageDef.bufferView]; | ||
const bufferDef = jsonDoc.json.buffers[bufferViewDef.buffer]; | ||
const bufferViewDef = json.bufferViews![imageDef.bufferView]; | ||
const bufferDef = jsonDoc.json.buffers![bufferViewDef.buffer]; | ||
const bufferData = bufferDef.uri | ||
@@ -214,5 +215,5 @@ ? jsonDoc.resources[bufferDef.uri] | ||
const textureInfoDef = pbrDef.baseColorTexture; | ||
const texture = context.textures[textureDefs[textureInfoDef.index].source]; | ||
const texture = context.textures[textureDefs[textureInfoDef.index].source!]; | ||
material.setBaseColorTexture(texture); | ||
context.setTextureInfo(material.getBaseColorTextureInfo(), textureInfoDef); | ||
context.setTextureInfo(material.getBaseColorTextureInfo()!, textureInfoDef); | ||
} | ||
@@ -222,5 +223,5 @@ | ||
const textureInfoDef = materialDef.emissiveTexture; | ||
const texture = context.textures[textureDefs[textureInfoDef.index].source]; | ||
const texture = context.textures[textureDefs[textureInfoDef.index].source!]; | ||
material.setEmissiveTexture(texture); | ||
context.setTextureInfo(material.getEmissiveTextureInfo(), textureInfoDef); | ||
context.setTextureInfo(material.getEmissiveTextureInfo()!, textureInfoDef); | ||
} | ||
@@ -230,5 +231,5 @@ | ||
const textureInfoDef = materialDef.normalTexture; | ||
const texture = context.textures[textureDefs[textureInfoDef.index].source]; | ||
const texture = context.textures[textureDefs[textureInfoDef.index].source!]; | ||
material.setNormalTexture(texture); | ||
context.setTextureInfo(material.getNormalTextureInfo(), textureInfoDef); | ||
context.setTextureInfo(material.getNormalTextureInfo()!, textureInfoDef); | ||
if (materialDef.normalTexture.scale !== undefined) { | ||
@@ -241,5 +242,5 @@ material.setNormalScale(materialDef.normalTexture.scale); | ||
const textureInfoDef = materialDef.occlusionTexture; | ||
const texture = context.textures[textureDefs[textureInfoDef.index].source]; | ||
const texture = context.textures[textureDefs[textureInfoDef.index].source!]; | ||
material.setOcclusionTexture(texture); | ||
context.setTextureInfo(material.getOcclusionTextureInfo(), textureInfoDef); | ||
context.setTextureInfo(material.getOcclusionTextureInfo()!, textureInfoDef); | ||
if (materialDef.occlusionTexture.strength !== undefined) { | ||
@@ -252,5 +253,5 @@ material.setOcclusionStrength(materialDef.occlusionTexture.strength); | ||
const textureInfoDef = pbrDef.metallicRoughnessTexture; | ||
const texture = context.textures[textureDefs[textureInfoDef.index].source]; | ||
const texture = context.textures[textureDefs[textureInfoDef.index].source!]; | ||
material.setMetallicRoughnessTexture(texture); | ||
context.setTextureInfo(material.getMetallicRoughnessTextureInfo(), textureInfoDef); | ||
context.setTextureInfo(material.getMetallicRoughnessTextureInfo()!, textureInfoDef); | ||
} | ||
@@ -298,3 +299,4 @@ | ||
const targetNames = meshDef.extras && meshDef.extras.targetNames || []; | ||
const targetNames: string[] = | ||
meshDef.extras && meshDef.extras.targetNames as string[] || []; | ||
const targetDefs = primitiveDef.targets || []; | ||
@@ -327,13 +329,18 @@ targetDefs.forEach((targetDef, targetIndex) => { | ||
if (cameraDef.type === Camera.Type.PERSPECTIVE) { | ||
camera | ||
.setZNear(cameraDef.perspective.znear) | ||
.setZFar(cameraDef.perspective.zfar) | ||
.setYFov(cameraDef.perspective.yfov) | ||
.setAspectRatio(cameraDef.perspective.aspectRatio); | ||
const perspectiveDef = cameraDef.perspective!; | ||
camera.setYFov(perspectiveDef.yfov); | ||
camera.setZNear(perspectiveDef.znear); | ||
if (perspectiveDef.zfar !== undefined) { | ||
camera.setZFar(perspectiveDef.zfar); | ||
} | ||
if (perspectiveDef.aspectRatio !== undefined) { | ||
camera.setAspectRatio(perspectiveDef.aspectRatio); | ||
} | ||
} else { | ||
const orthoDef = cameraDef.orthographic!; | ||
camera | ||
.setZNear(cameraDef.orthographic.znear) | ||
.setZFar(cameraDef.orthographic.zfar) | ||
.setXMag(cameraDef.orthographic.xmag) | ||
.setYMag(cameraDef.orthographic.ymag); | ||
.setZNear(orthoDef.znear) | ||
.setZFar(orthoDef.zfar) | ||
.setXMag(orthoDef.xmag) | ||
.setYMag(orthoDef.ymag); | ||
} | ||
@@ -477,2 +484,6 @@ return camera; | ||
if (json.scene !== undefined) { | ||
doc.getRoot().setDefaultScene(context.scenes[json.scene]); | ||
} | ||
/** Extensions (2/2). */ | ||
@@ -487,3 +498,3 @@ | ||
private static validate(jsonDoc: JSONDocument, options: ReaderOptions): void { | ||
private static validate(jsonDoc: JSONDocument, options: Required<ReaderOptions>): void { | ||
@@ -522,4 +533,4 @@ const json = jsonDoc.json; | ||
function getInterleavedArray(accessorDef: GLTF.IAccessor, jsonDoc: JSONDocument): TypedArray { | ||
const bufferViewDef = jsonDoc.json.bufferViews[accessorDef.bufferView]; | ||
const bufferDef = jsonDoc.json.buffers[bufferViewDef.buffer]; | ||
const bufferViewDef = jsonDoc.json.bufferViews![accessorDef.bufferView!]; | ||
const bufferDef = jsonDoc.json.buffers![bufferViewDef.buffer]; | ||
const resource = bufferDef.uri | ||
@@ -536,3 +547,3 @@ ? jsonDoc.resources[bufferDef.uri] | ||
const view = new DataView(resource, bufferViewDef.byteOffset, bufferViewDef.byteLength); | ||
const byteStride = bufferViewDef.byteStride; | ||
const byteStride = bufferViewDef.byteStride!; | ||
@@ -577,4 +588,4 @@ for (let i = 0; i < accessorDef.count; i++) { | ||
function getAccessorArray(accessorDef: GLTF.IAccessor, jsonDoc: JSONDocument): TypedArray { | ||
const bufferViewDef = jsonDoc.json.bufferViews[accessorDef.bufferView]; | ||
const bufferDef = jsonDoc.json.buffers[bufferViewDef.buffer]; | ||
const bufferViewDef = jsonDoc.json.bufferViews![accessorDef.bufferView!]; | ||
const bufferDef = jsonDoc.json.buffers![bufferViewDef.buffer]; | ||
const resource = bufferDef.uri | ||
@@ -630,5 +641,6 @@ ? jsonDoc.resources[bufferDef.uri] | ||
const count = accessorDef.sparse.count; | ||
const indicesDef = {...accessorDef, ...accessorDef.sparse.indices, count, type: 'SCALAR'}; | ||
const valuesDef = {...accessorDef, ...accessorDef.sparse.values, count}; | ||
const sparseDef = accessorDef.sparse!; | ||
const count = sparseDef.count; | ||
const indicesDef = {...accessorDef, ...sparseDef.indices, count, type: 'SCALAR'}; | ||
const valuesDef = {...accessorDef, ...sparseDef.values, count}; | ||
const indices = getAccessorArray(indicesDef as GLTF.IAccessor, jsonDoc); | ||
@@ -635,0 +647,0 @@ const values = getAccessorArray(valuesDef, jsonDoc); |
@@ -93,15 +93,17 @@ import { Document } from '../document'; | ||
const pendingResources: Array<Promise<void>> = [...images, ...buffers] | ||
.map((resource: GLTF.IBuffer|GLTF.IImage, index: number) => { | ||
if (!resource.uri) { | ||
.map((resource: GLTF.IBuffer|GLTF.IImage, index: number): Promise<void> => { | ||
const uri = resource.uri; | ||
if (!uri) { | ||
const isGLBBuffer = isGLB && index === images.length; | ||
if (resource['bufferView'] === undefined && !isGLBBuffer) { | ||
if ((resource as GLTF.IImage)['bufferView'] === undefined && !isGLBBuffer) { | ||
throw new Error('Missing resource URI.'); | ||
} | ||
return; | ||
return Promise.resolve(); | ||
} | ||
return fetch(_resolve(dir, resource.uri), this._fetchConfig) | ||
return fetch(_resolve(dir, uri), this._fetchConfig) | ||
.then((response) => response.arrayBuffer()) | ||
.then((arrayBuffer) => { | ||
jsonDoc.resources[resource.uri] = arrayBuffer; | ||
jsonDoc.resources[uri] = arrayBuffer; | ||
}); | ||
@@ -108,0 +110,0 @@ }); |
@@ -0,1 +1,3 @@ | ||
import { Format } from '../constants'; | ||
import { Document } from '../document'; | ||
import { JSONDocument } from '../json-document'; | ||
@@ -30,3 +32,3 @@ import { Accessor, Buffer, Camera, Material, Mesh, Node, Property, Skin, Texture, TextureInfo } from '../properties'; | ||
public readonly otherBufferViewsIndexMap = new Map<ArrayBuffer, number>(); | ||
public readonly extensionData = {}; | ||
public readonly extensionData: {[key: string]: unknown} = {}; | ||
@@ -40,3 +42,14 @@ public bufferURIGenerator: UniqueURIGenerator; | ||
constructor (public readonly jsonDoc: JSONDocument, public readonly options: WriterOptions) {} | ||
constructor ( | ||
doc: Document, | ||
public readonly jsonDoc: JSONDocument, | ||
public readonly options: Required<WriterOptions> | ||
) { | ||
const root = doc.getRoot(); | ||
const numBuffers = root.listBuffers().length; | ||
const numImages = root.listTextures().length; | ||
this.bufferURIGenerator = new UniqueURIGenerator(numBuffers > 1, options.basename); | ||
this.imageURIGenerator = new UniqueURIGenerator(numImages > 1, options.basename); | ||
this.logger = doc.getLogger(); | ||
} | ||
@@ -57,4 +70,4 @@ /** | ||
if (!this.samplerDefIndexMap.has(samplerKey)) { | ||
this.samplerDefIndexMap.set(samplerKey, this.jsonDoc.json.samplers.length); | ||
this.jsonDoc.json.samplers.push(samplerDef); | ||
this.samplerDefIndexMap.set(samplerKey, this.jsonDoc.json.samplers!.length); | ||
this.jsonDoc.json.samplers!.push(samplerDef); | ||
} | ||
@@ -69,4 +82,4 @@ | ||
if (!this.textureDefIndexMap.has(textureKey)) { | ||
this.textureDefIndexMap.set(textureKey, this.jsonDoc.json.textures.length); | ||
this.jsonDoc.json.textures.push(textureDef); | ||
this.textureDefIndexMap.set(textureKey, this.jsonDoc.json.textures!.length); | ||
this.jsonDoc.json.textures!.push(textureDef); | ||
} | ||
@@ -107,6 +120,6 @@ | ||
public createImageData(imageDef: GLTF.IImage, data: ArrayBuffer, texture: Texture): void { | ||
if (this.options.isGLB) { | ||
if (this.options.format === Format.GLB) { | ||
this.imageBufferViews.push(data); | ||
imageDef.bufferView = this.jsonDoc.json.bufferViews.length; | ||
this.jsonDoc.json.bufferViews.push({ | ||
imageDef.bufferView = this.jsonDoc.json.bufferViews!.length; | ||
this.jsonDoc.json.bufferViews!.push({ | ||
buffer: 0, | ||
@@ -128,4 +141,4 @@ byteOffset: -1, // determined while iterating buffers, in Writer.ts. | ||
*/ | ||
getAccessorUsage(accessor: Accessor): string { | ||
return this._accessorUsageMap.get(accessor); | ||
getAccessorUsage(accessor: Accessor): string | null { | ||
return this._accessorUsageMap.get(accessor) || null; | ||
} | ||
@@ -150,3 +163,3 @@ | ||
listAccessorsByUsage(): {[key: string]: Accessor[]} { | ||
const result = {}; | ||
const result = {} as {[key: string]: Accessor[]}; | ||
for (const [accessor, usage] of Array.from(this._accessorUsageMap.entries())) { | ||
@@ -153,0 +166,0 @@ result[usage] = result[usage] || []; |
@@ -1,2 +0,2 @@ | ||
import { GLB_BUFFER, NAME, PropertyType, VERSION, VertexLayout } from '../constants'; | ||
import { Format, GLB_BUFFER, NAME, PropertyType, VERSION, VertexLayout } from '../constants'; | ||
import { Document } from '../document'; | ||
@@ -8,3 +8,3 @@ import { Link } from '../graph'; | ||
import { BufferUtils, Logger, MathUtils } from '../utils'; | ||
import { UniqueURIGenerator, WriterContext } from './writer-context'; | ||
import { WriterContext } from './writer-context'; | ||
@@ -24,5 +24,5 @@ const BufferViewTarget = { | ||
export interface WriterOptions { | ||
format: Format; | ||
logger?: Logger; | ||
basename?: string; | ||
isGLB?: boolean; | ||
vertexLayout?: VertexLayout, | ||
@@ -32,32 +32,18 @@ dependencies?: {[key: string]: unknown}; | ||
const DEFAULT_OPTIONS: WriterOptions = { | ||
logger: Logger.DEFAULT_INSTANCE, | ||
basename: '', | ||
isGLB: true, | ||
vertexLayout: VertexLayout.INTERLEAVED, | ||
dependencies: {}, | ||
}; | ||
/** @hidden */ | ||
export class GLTFWriter { | ||
public static write(doc: Document, options: WriterOptions = DEFAULT_OPTIONS): JSONDocument { | ||
public static write(doc: Document, options: Required<WriterOptions>): JSONDocument { | ||
const root = doc.getRoot(); | ||
const jsonDoc = {json: {asset: root.getAsset()}, resources: {}} as JSONDocument; | ||
const logger = options.logger || Logger.DEFAULT_INSTANCE; | ||
const json = jsonDoc.json; | ||
json.asset.generator = `glTF-Transform ${VERSION}`; | ||
/* Writer context. */ | ||
const context = new WriterContext(doc, jsonDoc, options); | ||
const logger = options.logger || Logger.DEFAULT_INSTANCE; | ||
const context = new WriterContext(jsonDoc, options); | ||
const numBuffers = root.listBuffers().length; | ||
const numImages = root.listTextures().length; | ||
context.bufferURIGenerator = new UniqueURIGenerator(numBuffers > 1, options.basename); | ||
context.imageURIGenerator = new UniqueURIGenerator(numImages > 1, options.basename); | ||
context.logger = doc.getLogger(); | ||
/* Extensions (1/2). */ | ||
for (const extension of doc.getRoot().listExtensionsUsed()) { | ||
for (const key of extension.dependencies) { | ||
for (const key of extension.writeDependencies) { | ||
extension.install(key, options.dependencies[key]); | ||
@@ -94,5 +80,5 @@ } | ||
const accessorDef = context.createAccessorDef(accessor); | ||
accessorDef.bufferView = json.bufferViews.length; | ||
accessorDef.bufferView = json.bufferViews!.length; | ||
const data = BufferUtils.pad(accessor.getArray().buffer); | ||
const data = BufferUtils.pad(accessor.getArray()!.buffer); | ||
accessorDef.byteOffset = byteLength; | ||
@@ -102,4 +88,4 @@ byteLength += data.byteLength; | ||
context.accessorIndexMap.set(accessor, json.accessors.length); | ||
json.accessors.push(accessorDef); | ||
context.accessorIndexMap.set(accessor, json.accessors!.length); | ||
json.accessors!.push(accessorDef); | ||
} | ||
@@ -115,3 +101,3 @@ | ||
if (bufferViewTarget) bufferViewDef.target = bufferViewTarget; | ||
json.bufferViews.push(bufferViewDef); | ||
json.bufferViews!.push(bufferViewDef); | ||
@@ -143,3 +129,3 @@ return {buffers, byteLength}; | ||
const accessorDef = context.createAccessorDef(accessor); | ||
accessorDef.bufferView = json.bufferViews.length; | ||
accessorDef.bufferView = json.bufferViews!.length; | ||
accessorDef.byteOffset = byteStride; | ||
@@ -151,4 +137,4 @@ | ||
context.accessorIndexMap.set(accessor, json.accessors.length); | ||
json.accessors.push(accessorDef); | ||
context.accessorIndexMap.set(accessor, json.accessors!.length); | ||
json.accessors!.push(accessorDef); | ||
} | ||
@@ -168,3 +154,3 @@ | ||
const componentType = accessor.getComponentType(); | ||
const array = accessor.getArray(); | ||
const array = accessor.getArray()!; | ||
for (let j = 0; j < elementSize; j++) { | ||
@@ -209,3 +195,3 @@ const viewByteOffset = | ||
}; | ||
json.bufferViews.push(bufferViewDef); | ||
json.bufferViews!.push(bufferViewDef); | ||
@@ -249,4 +235,5 @@ return {byteLength, buffers: [buffer]}; | ||
if (texture.getImage()) { | ||
context.createImageData(imageDef, texture.getImage(), texture); | ||
const image = texture.getImage(); | ||
if (image) { | ||
context.createImageData(imageDef, image, texture); | ||
} | ||
@@ -308,3 +295,4 @@ | ||
// attributes) organize buffer views accordingly. | ||
if (groupByParent.has(context.getAccessorUsage(accessor))) { | ||
const usage = context.getAccessorUsage(accessor); | ||
if (usage && groupByParent.has(usage)) { | ||
const parent = accessorRefs[0].getParent(); | ||
@@ -320,3 +308,3 @@ const parentAccessors = accessorParents.get(parent) || new Set<Accessor>(); | ||
const buffers: ArrayBuffer[] = []; | ||
const bufferIndex = json.buffers.length; | ||
const bufferIndex = json.buffers!.length; | ||
let bufferByteLength = 0; | ||
@@ -370,3 +358,3 @@ | ||
? BufferViewTarget.ELEMENT_ARRAY_BUFFER | ||
: null; | ||
: undefined; | ||
const result = concatAccessors( | ||
@@ -383,3 +371,3 @@ accessors, bufferIndex, bufferByteLength, target | ||
for (let i = 0; i < context.imageBufferViews.length; i++) { | ||
json.bufferViews[json.images[i].bufferView].byteOffset = bufferByteLength; | ||
json.bufferViews![json.images![i].bufferView!].byteOffset = bufferByteLength; | ||
bufferByteLength += context.imageBufferViews[i].byteLength; | ||
@@ -398,4 +386,4 @@ buffers.push(context.imageBufferViews[i]); | ||
if (context.otherBufferViews.has(buffer)) { | ||
for (const data of context.otherBufferViews.get(buffer)) { | ||
json.bufferViews.push({ | ||
for (const data of context.otherBufferViews.get(buffer)!) { | ||
json.bufferViews!.push({ | ||
buffer: bufferIndex, | ||
@@ -405,3 +393,3 @@ byteOffset: bufferByteLength, | ||
}); | ||
context.otherBufferViewsIndexMap.set(data, json.bufferViews.length - 1); | ||
context.otherBufferViewsIndexMap.set(data, json.bufferViews!.length - 1); | ||
bufferByteLength += data.byteLength; | ||
@@ -420,3 +408,3 @@ buffers.push(data); | ||
let uri: string; | ||
if (options.isGLB) { | ||
if (options.format === Format.GLB) { | ||
uri = GLB_BUFFER; | ||
@@ -433,3 +421,3 @@ } else { | ||
json.buffers.push(bufferDef); | ||
json.buffers!.push(bufferDef); | ||
}); | ||
@@ -465,4 +453,4 @@ | ||
if (material.getBaseColorTexture()) { | ||
const texture = material.getBaseColorTexture(); | ||
const textureInfo = material.getBaseColorTextureInfo(); | ||
const texture = material.getBaseColorTexture()!; | ||
const textureInfo = material.getBaseColorTextureInfo()!; | ||
materialDef.pbrMetallicRoughness.baseColorTexture | ||
@@ -473,4 +461,4 @@ = context.createTextureInfoDef(texture, textureInfo); | ||
if (material.getEmissiveTexture()) { | ||
const texture = material.getEmissiveTexture(); | ||
const textureInfo = material.getEmissiveTextureInfo(); | ||
const texture = material.getEmissiveTexture()!; | ||
const textureInfo = material.getEmissiveTextureInfo()!; | ||
materialDef.emissiveTexture = context.createTextureInfoDef(texture, textureInfo); | ||
@@ -480,4 +468,4 @@ } | ||
if (material.getNormalTexture()) { | ||
const texture = material.getNormalTexture(); | ||
const textureInfo = material.getNormalTextureInfo(); | ||
const texture = material.getNormalTexture()!; | ||
const textureInfo = material.getNormalTextureInfo()!; | ||
const textureInfoDef = context.createTextureInfoDef(texture, textureInfo) as | ||
@@ -492,4 +480,4 @@ GLTF.IMaterialNormalTextureInfo; | ||
if (material.getOcclusionTexture()) { | ||
const texture = material.getOcclusionTexture(); | ||
const textureInfo = material.getOcclusionTextureInfo(); | ||
const texture = material.getOcclusionTexture()!; | ||
const textureInfo = material.getOcclusionTextureInfo()!; | ||
const textureInfoDef = context.createTextureInfoDef(texture, textureInfo) as | ||
@@ -504,4 +492,4 @@ GLTF.IMaterialOcclusionTextureInfo; | ||
if (material.getMetallicRoughnessTexture()) { | ||
const texture = material.getMetallicRoughnessTexture(); | ||
const textureInfo = material.getMetallicRoughnessTextureInfo(); | ||
const texture = material.getMetallicRoughnessTexture()!; | ||
const textureInfo = material.getMetallicRoughnessTextureInfo()!; | ||
materialDef.pbrMetallicRoughness.metallicRoughnessTexture | ||
@@ -520,3 +508,3 @@ = context.createTextureInfoDef(texture, textureInfo); | ||
let targetNames: string[]; | ||
let targetNames: string[] | null = null; | ||
@@ -528,4 +516,5 @@ meshDef.primitives = mesh.listPrimitives().map((primitive) => { | ||
if (primitive.getMaterial()) { | ||
primitiveDef.material = context.materialIndexMap.get(primitive.getMaterial()); | ||
const material = primitive.getMaterial(); | ||
if (material) { | ||
primitiveDef.material = context.materialIndexMap.get(material); | ||
} | ||
@@ -537,4 +526,5 @@ | ||
if (primitive.getIndices()) { | ||
primitiveDef.indices = context.accessorIndexMap.get(primitive.getIndices()); | ||
const indices = primitive.getIndices(); | ||
if (indices) { | ||
primitiveDef.indices = context.accessorIndexMap.get(indices); | ||
} | ||
@@ -544,11 +534,11 @@ | ||
primitiveDef.attributes[semantic] | ||
= context.accessorIndexMap.get(primitive.getAttribute(semantic)); | ||
= context.accessorIndexMap.get(primitive.getAttribute(semantic)!)!; | ||
} | ||
for (const target of primitive.listTargets()) { | ||
const targetDef = {}; | ||
const targetDef = {} as {[name: string]: number}; | ||
for (const semantic of target.listSemantics()) { | ||
targetDef[semantic] | ||
= context.accessorIndexMap.get(target.getAttribute(semantic)); | ||
= context.accessorIndexMap.get(target.getAttribute(semantic)!)!; | ||
} | ||
@@ -590,4 +580,7 @@ | ||
yfov: camera.getYFov(), | ||
aspectRatio: camera.getAspectRatio(), | ||
}; | ||
const aspectRatio = camera.getAspectRatio(); | ||
if (aspectRatio !== null) { | ||
cameraDef.perspective.aspectRatio = aspectRatio; | ||
} | ||
} else { | ||
@@ -638,12 +631,13 @@ cameraDef.orthographic = { | ||
if (skin.getInverseBindMatrices()) { | ||
skinDef.inverseBindMatrices | ||
= context.accessorIndexMap.get(skin.getInverseBindMatrices()); | ||
const inverseBindMatrices = skin.getInverseBindMatrices(); | ||
if (inverseBindMatrices) { | ||
skinDef.inverseBindMatrices = context.accessorIndexMap.get(inverseBindMatrices); | ||
} | ||
if (skin.getSkeleton()) { | ||
skinDef.skeleton = context.nodeIndexMap.get(skin.getSkeleton()); | ||
const skeleton = skin.getSkeleton(); | ||
if (skeleton) { | ||
skinDef.skeleton = context.nodeIndexMap.get(skeleton); | ||
} | ||
skinDef.joints = skin.listJoints().map((joint) => context.nodeIndexMap.get(joint)); | ||
skinDef.joints = skin.listJoints().map((joint) => context.nodeIndexMap.get(joint)!); | ||
@@ -657,14 +651,17 @@ context.skinIndexMap.set(skin, index); | ||
root.listNodes().forEach((node, index) => { | ||
const nodeDef = json.nodes[index]; | ||
const nodeDef = json.nodes![index]; | ||
if (node.getMesh()) { | ||
nodeDef.mesh = context.meshIndexMap.get(node.getMesh()); | ||
const mesh = node.getMesh(); | ||
if (mesh) { | ||
nodeDef.mesh = context.meshIndexMap.get(mesh); | ||
} | ||
if (node.getCamera()) { | ||
nodeDef.camera = context.cameraIndexMap.get(node.getCamera()); | ||
const camera = node.getCamera(); | ||
if (camera) { | ||
nodeDef.camera = context.cameraIndexMap.get(camera); | ||
} | ||
if (node.getSkin()) { | ||
nodeDef.skin = context.skinIndexMap.get(node.getSkin()); | ||
const skin = node.getSkin(); | ||
if (skin) { | ||
nodeDef.skin = context.skinIndexMap.get(skin); | ||
} | ||
@@ -674,3 +671,3 @@ | ||
nodeDef.children = node.listChildren() | ||
.map((node) => context.nodeIndexMap.get(node)); | ||
.map((node) => context.nodeIndexMap.get(node)!); | ||
} | ||
@@ -689,4 +686,4 @@ }); | ||
const samplerDef = context.createPropertyDef(sampler) as GLTF.IAnimationSampler; | ||
samplerDef.input = context.accessorIndexMap.get(sampler.getInput()); | ||
samplerDef.output = context.accessorIndexMap.get(sampler.getOutput()); | ||
samplerDef.input = context.accessorIndexMap.get(sampler.getInput()!)!; | ||
samplerDef.output = context.accessorIndexMap.get(sampler.getOutput()!)!; | ||
samplerDef.interpolation = sampler.getInterpolation(); | ||
@@ -700,6 +697,6 @@ samplerIndexMap.set(sampler, samplerIndex); | ||
const channelDef = context.createPropertyDef(channel) as GLTF.IAnimationChannel; | ||
channelDef.sampler = samplerIndexMap.get(channel.getSampler()); | ||
channelDef.sampler = samplerIndexMap.get(channel.getSampler()!)!; | ||
channelDef.target = { | ||
node: context.nodeIndexMap.get(channel.getTargetNode()), | ||
path: channel.getTargetPath(), | ||
node: context.nodeIndexMap.get(channel.getTargetNode()!)!, | ||
path: channel.getTargetPath()!, | ||
}; | ||
@@ -716,6 +713,11 @@ return channelDef; | ||
const sceneDef = context.createPropertyDef(scene) as GLTF.IScene; | ||
sceneDef.nodes = scene.listChildren().map((node) => context.nodeIndexMap.get(node)); | ||
sceneDef.nodes = scene.listChildren().map((node) => context.nodeIndexMap.get(node)!); | ||
return sceneDef; | ||
}); | ||
const defaultScene = root.getDefaultScene(); | ||
if (defaultScene) { | ||
json.scene = root.listScenes().indexOf(defaultScene); | ||
} | ||
/* Extensions (2/2). */ | ||
@@ -729,3 +731,3 @@ | ||
clean(json); | ||
clean(json as unknown as Record<string, unknown>); | ||
@@ -741,3 +743,3 @@ return jsonDoc; | ||
*/ | ||
function clean(object): void { | ||
function clean(object: Record<string, unknown>): void { | ||
const unused: string[] = []; | ||
@@ -750,3 +752,3 @@ | ||
} else if (value === null || value === '') { | ||
unused.push(value); | ||
unused.push(key); | ||
} | ||
@@ -753,0 +755,0 @@ } |
@@ -99,4 +99,5 @@ import { PropertyType, TypedArray } from '../constants'; | ||
if (other._array) this._array = other._array.slice(); | ||
if (other.buffer) this.setBuffer(resolve(other.buffer.getChild())); | ||
this.setBuffer(other.buffer ? resolve(other.buffer.getChild()) : null); | ||
return this; | ||
@@ -403,3 +404,3 @@ } | ||
/** Assigns the {@link Buffer} into which this accessor will be organized. */ | ||
public setBuffer(buffer: Buffer): this { | ||
public setBuffer(buffer: Buffer | null): this { | ||
this.buffer = this.graph.link('buffer', this, buffer); | ||
@@ -406,0 +407,0 @@ return this; |
@@ -48,4 +48,4 @@ import { PropertyType } from '../constants'; | ||
if (other.targetNode) this.setTargetNode(resolve(other.targetNode.getChild())); | ||
if (other.sampler) this.setSampler(resolve(other.sampler.getChild())); | ||
this.setTargetNode(other.targetNode ? resolve(other.targetNode.getChild()) : null); | ||
this.setSampler(other.sampler ? resolve(other.sampler.getChild()) : null); | ||
@@ -98,3 +98,3 @@ return this; | ||
/** Target {@link Node} animated by the channel. */ | ||
public setTargetNode(targetNode: Node): this { | ||
public setTargetNode(targetNode: Node | null): this { | ||
this.targetNode = this.graph.link('target.node', this, targetNode); | ||
@@ -116,3 +116,3 @@ return this; | ||
*/ | ||
public setSampler(sampler: AnimationSampler): this { | ||
public setSampler(sampler: AnimationSampler | null): this { | ||
this.sampler = this.graph.link('sampler', this, sampler); | ||
@@ -119,0 +119,0 @@ return this; |
@@ -62,4 +62,4 @@ import { PropertyType } from '../constants'; | ||
if (other.input) this.setInput(resolve(other.input.getChild())); | ||
if (other.output) this.setOutput(resolve(other.output.getChild())); | ||
this.setInput(other.input ? resolve(other.input.getChild()) : null); | ||
this.setOutput(other.output ? resolve(other.output.getChild()) : null); | ||
@@ -66,0 +66,0 @@ return this; |
@@ -34,2 +34,3 @@ import { ExtensibleProperty } from './extensible-property'; | ||
/** @hidden */ | ||
constructor(graph: PropertyGraph, private readonly _extension: ExtensionPropertyParent) { | ||
@@ -36,0 +37,0 @@ super(graph); |
@@ -134,28 +134,34 @@ import { PropertyType, TextureChannel, vec3, vec4 } from '../constants'; | ||
if (other.baseColorTexture) { | ||
this.setBaseColorTexture(resolve(other.baseColorTexture.getChild())); | ||
this.getBaseColorTextureInfo() | ||
.copy(resolve(other.baseColorTextureInfo.getChild()), resolve); | ||
} | ||
if (other.emissiveTexture) { | ||
this.setEmissiveTexture(resolve(other.emissiveTexture.getChild())); | ||
this.getEmissiveTextureInfo() | ||
.copy(resolve(other.emissiveTextureInfo.getChild()), resolve); | ||
} | ||
if (other.normalTexture) { | ||
this.setNormalTexture(resolve(other.normalTexture.getChild())); | ||
this.getNormalTextureInfo() | ||
.copy(resolve(other.normalTextureInfo.getChild()), resolve); | ||
} | ||
if (other.occlusionTexture) { | ||
this.setOcclusionTexture(resolve(other.occlusionTexture.getChild())); | ||
this.getOcclusionTextureInfo() | ||
.copy(resolve(other.occlusionTextureInfo.getChild()), resolve); | ||
} | ||
if (other.metallicRoughnessTexture) { | ||
this.setMetallicRoughnessTexture(resolve(other.metallicRoughnessTexture.getChild())); | ||
this.getMetallicRoughnessTextureInfo() | ||
.copy(resolve(other.metallicRoughnessTextureInfo.getChild()), resolve); | ||
} | ||
this.setBaseColorTexture( | ||
other.baseColorTexture ? resolve(other.baseColorTexture.getChild()) : null | ||
); | ||
this.baseColorTextureInfo.getChild() | ||
.copy(resolve(other.baseColorTextureInfo.getChild()), resolve); | ||
this.setEmissiveTexture( | ||
other.emissiveTexture ? resolve(other.emissiveTexture.getChild()) : null | ||
); | ||
this.emissiveTextureInfo.getChild() | ||
.copy(resolve(other.emissiveTextureInfo.getChild()), resolve); | ||
this.setNormalTexture( | ||
other.normalTexture ? resolve(other.normalTexture.getChild()) : null | ||
); | ||
this.normalTextureInfo.getChild() | ||
.copy(resolve(other.normalTextureInfo.getChild()), resolve); | ||
this.setOcclusionTexture( | ||
other.occlusionTexture ? resolve(other.occlusionTexture.getChild()) : null | ||
); | ||
this.occlusionTextureInfo.getChild() | ||
.copy(resolve(other.occlusionTextureInfo.getChild()), resolve); | ||
this.setMetallicRoughnessTexture( | ||
other.metallicRoughnessTexture | ||
? resolve(other.metallicRoughnessTexture.getChild()) | ||
: null | ||
); | ||
this.metallicRoughnessTextureInfo.getChild() | ||
.copy(resolve(other.metallicRoughnessTextureInfo.getChild()), resolve); | ||
return this; | ||
@@ -162,0 +168,0 @@ } |
@@ -63,5 +63,5 @@ import { multiply } from 'gl-matrix/mat4'; | ||
if (other.camera) this.setCamera(resolve(other.camera.getChild())); | ||
if (other.mesh) this.setMesh(resolve(other.mesh.getChild())); | ||
if (other.skin) this.setSkin(resolve(other.skin.getChild())); | ||
this.setCamera(other.camera ? resolve(other.camera.getChild()) : null); | ||
this.setMesh(other.mesh ? resolve(other.mesh.getChild()) : null); | ||
this.setSkin(other.skin ? resolve(other.skin.getChild()) : null); | ||
@@ -68,0 +68,0 @@ if (resolve !== COPY_IDENTITY) { |
@@ -24,3 +24,3 @@ import { PropertyType } from '../constants'; | ||
* behavior is necessary (like raycasting or collisions) prefer to assign each primitive to a | ||
* different mesh. The number of GPU draw calls is typically not unaffected by grouping or | ||
* different mesh. The number of GPU draw calls is typically not affected by grouping or | ||
* ungrouping primitives to a mesh. | ||
@@ -63,4 +63,4 @@ * | ||
if (other.indices) this.setIndices(resolve(other.indices.getChild())); | ||
if (other.material) this.setMaterial(resolve(other.material.getChild())); | ||
this.setIndices(other.indices ? resolve(other.indices.getChild()) : null); | ||
this.setMaterial(other.material ? resolve(other.material.getChild()) : null); | ||
@@ -67,0 +67,0 @@ this.clearGraphChildList(this.attributes); |
import { PropertyType, VERSION } from '../constants'; | ||
import { Extension } from '../extension'; | ||
import { GraphChildList, Link } from '../graph/index'; | ||
import { GraphChild, GraphChildList, Link } from '../graph'; | ||
import { GLTF } from '../types/gltf'; | ||
@@ -60,2 +60,4 @@ import { Accessor } from './accessor'; | ||
@GraphChild private defaultScene: Link<Root, Scene> | null = null; | ||
@GraphChildList private accessors: Link<Root, Accessor>[] = []; | ||
@@ -102,2 +104,4 @@ @GraphChildList private animations: Link<Root, Animation>[] = []; | ||
this.setDefaultScene(other.defaultScene ? resolve(other.defaultScene.getChild()) : null); | ||
return this; | ||
@@ -185,2 +189,13 @@ } | ||
/** Default {@link Scene} associated with this root. */ | ||
public setDefaultScene(defaultScene: Scene | null): this { | ||
this.defaultScene = this.graph.link('scene', this, defaultScene); | ||
return this; | ||
} | ||
/** Default {@link Scene} associated with this root. */ | ||
public getDefaultScene(): Scene | null { | ||
return this.defaultScene ? this.defaultScene.getChild() : null; | ||
} | ||
/********************************************************************************************** | ||
@@ -187,0 +202,0 @@ * Nodes. |
@@ -29,6 +29,6 @@ import { PropertyType } from '../constants'; | ||
if (other.skeleton) this.setSkeleton(resolve(other.skeleton.getChild())); | ||
if (other.inverseBindMatrices) { | ||
this.setInverseBindMatrices(resolve(other.inverseBindMatrices.getChild())); | ||
} | ||
this.setSkeleton(other.skeleton ? resolve(other.skeleton.getChild()) : null); | ||
this.setInverseBindMatrices( | ||
other.inverseBindMatrices ? resolve(other.inverseBindMatrices.getChild()) : null | ||
); | ||
@@ -35,0 +35,0 @@ this.clearGraphChildList(this.joints); |
@@ -11,3 +11,3 @@ /** | ||
static basename(path: string): string { | ||
const fileName = path.split(/[\\/]/).pop(); | ||
const fileName = path.split(/[\\/]/).pop()!; | ||
return fileName.substr(0, fileName.lastIndexOf('.')); | ||
@@ -19,3 +19,3 @@ } | ||
if (path.indexOf('data:') !== 0) { | ||
return path.split(/[\\/]/).pop().split(/[.]/).pop(); | ||
return path.split(/[\\/]/).pop()!.split(/[.]/).pop()!; | ||
} else if (path.indexOf('data:image/png') === 0) { | ||
@@ -22,0 +22,0 @@ return 'png'; |
@@ -5,5 +5,5 @@ import { vec2 } from '../constants'; | ||
export interface ImageUtilsFormat { | ||
getSize(buffer: ArrayBuffer): vec2; | ||
getChannels(buffer: ArrayBuffer): number; | ||
getGPUByteLength?(buffer: ArrayBuffer): number; | ||
getSize(buffer: ArrayBuffer): vec2 | null; | ||
getChannels(buffer: ArrayBuffer): number | null; | ||
getGPUByteLength?(buffer: ArrayBuffer): number | null; | ||
} | ||
@@ -84,3 +84,3 @@ | ||
/** Returns the dimensions of the image. */ | ||
public static getSize (buffer: ArrayBuffer, mimeType: string): vec2 { | ||
public static getSize (buffer: ArrayBuffer, mimeType: string): vec2 | null { | ||
if (!this.impls[mimeType]) return null; | ||
@@ -95,3 +95,3 @@ return this.impls[mimeType].getSize(buffer); | ||
*/ | ||
public static getChannels (buffer: ArrayBuffer, mimeType: string): number { | ||
public static getChannels (buffer: ArrayBuffer, mimeType: string): number | null { | ||
if (!this.impls[mimeType]) return null; | ||
@@ -102,7 +102,7 @@ return this.impls[mimeType].getChannels(buffer); | ||
/** Returns a conservative estimate of the GPU memory required by this image. */ | ||
public static getMemSize (buffer: ArrayBuffer, mimeType: string): number { | ||
public static getMemSize (buffer: ArrayBuffer, mimeType: string): number | null { | ||
if (!this.impls[mimeType]) return null; | ||
if (this.impls[mimeType].getGPUByteLength) { | ||
return this.impls[mimeType].getGPUByteLength(buffer); | ||
return this.impls[mimeType].getGPUByteLength!(buffer); | ||
} | ||
@@ -113,2 +113,4 @@ | ||
const resolution = this.getSize(buffer, mimeType); | ||
if (!resolution) return null; | ||
while (resolution[0] > 1 || resolution[1] > 1) { | ||
@@ -126,3 +128,3 @@ uncompressedBytes += resolution[0] * resolution[1] * channels; | ||
if (mimeType === 'image/jpeg') return 'jpg'; | ||
return mimeType.split('/').pop(); | ||
return mimeType.split('/').pop()!; | ||
} | ||
@@ -129,0 +131,0 @@ |
@@ -5,5 +5,4 @@ export * from './buffer-utils'; | ||
export * from './image-utils'; | ||
export * from './graph-utils'; | ||
export * from './math-utils'; | ||
export * from './logger'; | ||
export * from './uuid'; |
@@ -107,3 +107,3 @@ import { determinant, getRotation } from 'gl-matrix/mat4'; | ||
getRotation(dstRotation, _m1); | ||
getRotation(dstRotation, _m1 as mat4); | ||
@@ -110,0 +110,0 @@ dstScale[0] = sx; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
1246166
10985
106