@loaders.gl/gltf
Version:
Framework-independent loader for the glTF format
1,429 lines (1,418 loc) • 141 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name12 in all)
__defProp(target, name12, { get: all[name12], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// dist/index.js
var dist_exports = {};
__export(dist_exports, {
EXT_FEATURE_METADATA: () => name3,
EXT_MESH_FEATURES: () => name,
EXT_STRUCTURAL_METADATA: () => name2,
GLBLoader: () => GLBLoader,
GLBWriter: () => GLBWriter,
GLTFLoader: () => GLTFLoader,
GLTFScenegraph: () => GLTFScenegraph,
GLTFWriter: () => GLTFWriter,
_getMemoryUsageGLTF: () => getMemoryUsageGLTF,
createExtMeshFeatures: () => createExtMeshFeatures,
createExtStructuralMetadata: () => createExtStructuralMetadata,
postProcessGLTF: () => postProcessGLTF
});
module.exports = __toCommonJS(dist_exports);
// dist/lib/extensions/EXT_mesh_features.js
var EXT_mesh_features_exports = {};
__export(EXT_mesh_features_exports, {
createExtMeshFeatures: () => createExtMeshFeatures,
decode: () => decode,
encode: () => encode,
name: () => name
});
// dist/lib/api/gltf-scenegraph.js
var import_images = require("@loaders.gl/images");
var import_loader_utils = require("@loaders.gl/loader-utils");
// dist/lib/utils/assert.js
function assert(condition, message) {
if (!condition) {
throw new Error(message || "assert failed: gltf");
}
}
// dist/lib/gltf-utils/gltf-constants.js
var COMPONENTS = {
SCALAR: 1,
VEC2: 2,
VEC3: 3,
VEC4: 4,
MAT2: 4,
MAT3: 9,
MAT4: 16
};
var BYTES = {
5120: 1,
// BYTE
5121: 1,
// UNSIGNED_BYTE
5122: 2,
// SHORT
5123: 2,
// UNSIGNED_SHORT
5125: 4,
// UNSIGNED_INT
5126: 4
// FLOAT
};
// dist/lib/gltf-utils/gltf-utils.js
var MIPMAP_FACTOR = 1.33;
var TYPES = ["SCALAR", "VEC2", "VEC3", "VEC4"];
var ARRAY_CONSTRUCTOR_TO_WEBGL_CONSTANT = [
[Int8Array, 5120],
[Uint8Array, 5121],
[Int16Array, 5122],
[Uint16Array, 5123],
[Uint32Array, 5125],
[Float32Array, 5126],
[Float64Array, 5130]
];
var ARRAY_TO_COMPONENT_TYPE = new Map(ARRAY_CONSTRUCTOR_TO_WEBGL_CONSTANT);
var ATTRIBUTE_TYPE_TO_COMPONENTS = {
SCALAR: 1,
VEC2: 2,
VEC3: 3,
VEC4: 4,
MAT2: 4,
MAT3: 9,
MAT4: 16
};
var ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE = {
5120: 1,
5121: 1,
5122: 2,
5123: 2,
5125: 4,
5126: 4
};
var ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY = {
5120: Int8Array,
5121: Uint8Array,
5122: Int16Array,
5123: Uint16Array,
5125: Uint32Array,
5126: Float32Array
};
function getAccessorTypeFromSize(size) {
const type = TYPES[size - 1];
return type || TYPES[0];
}
function getComponentTypeFromArray(typedArray) {
const componentType = ARRAY_TO_COMPONENT_TYPE.get(typedArray.constructor);
if (!componentType) {
throw new Error("Illegal typed array");
}
return componentType;
}
function getAccessorArrayTypeAndLength(accessor, bufferView) {
const ArrayType = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[accessor.componentType];
const components = ATTRIBUTE_TYPE_TO_COMPONENTS[accessor.type];
const bytesPerComponent = ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE[accessor.componentType];
const length = accessor.count * components;
const byteLength = accessor.count * components * bytesPerComponent;
assert(byteLength >= 0 && byteLength <= bufferView.byteLength);
const componentByteSize = BYTES[accessor.componentType];
const numberOfComponentsInElement = COMPONENTS[accessor.type];
return { ArrayType, length, byteLength, componentByteSize, numberOfComponentsInElement };
}
function getMemoryUsageGLTF(gltf) {
let { images, bufferViews } = gltf;
images = images || [];
bufferViews = bufferViews || [];
const imageBufferViews = images.map((i) => i.bufferView);
bufferViews = bufferViews.filter((view) => !imageBufferViews.includes(view));
const bufferMemory = bufferViews.reduce((acc, view) => acc + view.byteLength, 0);
const pixelCount = images.reduce((acc, image) => {
const { width, height } = image.image;
return acc + width * height;
}, 0);
return bufferMemory + Math.ceil(4 * pixelCount * MIPMAP_FACTOR);
}
// dist/lib/gltf-utils/get-typed-array.js
function getTypedArrayForBufferView(json, buffers, bufferViewIndex) {
const bufferView = json.bufferViews[bufferViewIndex];
assert(bufferView);
const bufferIndex = bufferView.buffer;
const binChunk = buffers[bufferIndex];
assert(binChunk);
const byteOffset = (bufferView.byteOffset || 0) + binChunk.byteOffset;
return new Uint8Array(binChunk.arrayBuffer, byteOffset, bufferView.byteLength);
}
function getTypedArrayForAccessor(json, buffers, accessor) {
var _a, _b;
const gltfAccessor = typeof accessor === "number" ? (_a = json.accessors) == null ? void 0 : _a[accessor] : accessor;
if (!gltfAccessor) {
throw new Error(`No gltf accessor ${JSON.stringify(accessor)}`);
}
const bufferView = (_b = json.bufferViews) == null ? void 0 : _b[gltfAccessor.bufferView || 0];
if (!bufferView) {
throw new Error(`No gltf buffer view for accessor ${bufferView}`);
}
const { arrayBuffer, byteOffset: bufferByteOffset } = buffers[bufferView.buffer];
const byteOffset = (bufferByteOffset || 0) + (gltfAccessor.byteOffset || 0) + (bufferView.byteOffset || 0);
const { ArrayType, length, componentByteSize, numberOfComponentsInElement } = getAccessorArrayTypeAndLength(gltfAccessor, bufferView);
const elementByteSize = componentByteSize * numberOfComponentsInElement;
const elementAddressScale = bufferView.byteStride || elementByteSize;
if (typeof bufferView.byteStride === "undefined" || bufferView.byteStride === elementByteSize) {
const result2 = new ArrayType(arrayBuffer, byteOffset, length);
return result2;
}
const result = new ArrayType(length);
for (let i = 0; i < gltfAccessor.count; i++) {
const values = new ArrayType(arrayBuffer, byteOffset + i * elementAddressScale, numberOfComponentsInElement);
result.set(values, i * numberOfComponentsInElement);
}
return result;
}
// dist/lib/api/gltf-scenegraph.js
function makeDefaultGLTFJson() {
return {
asset: {
version: "2.0",
generator: "loaders.gl"
},
buffers: [],
extensions: {},
extensionsRequired: [],
extensionsUsed: []
};
}
var GLTFScenegraph = class {
// internal
gltf;
sourceBuffers;
byteLength;
// TODO - why is this not GLTFWithBuffers - what happens to images?
constructor(gltf) {
this.gltf = {
json: (gltf == null ? void 0 : gltf.json) || makeDefaultGLTFJson(),
buffers: (gltf == null ? void 0 : gltf.buffers) || [],
images: (gltf == null ? void 0 : gltf.images) || []
};
this.sourceBuffers = [];
this.byteLength = 0;
if (this.gltf.buffers && this.gltf.buffers[0]) {
this.byteLength = this.gltf.buffers[0].byteLength;
this.sourceBuffers = [this.gltf.buffers[0]];
}
}
// Accessors
get json() {
return this.gltf.json;
}
getApplicationData(key) {
const data = this.json[key];
return data;
}
getExtraData(key) {
const extras = this.json.extras || {};
return extras[key];
}
hasExtension(extensionName) {
const isUsedExtension = this.getUsedExtensions().find((name12) => name12 === extensionName);
const isRequiredExtension = this.getRequiredExtensions().find((name12) => name12 === extensionName);
return typeof isUsedExtension === "string" || typeof isRequiredExtension === "string";
}
getExtension(extensionName) {
const isExtension = this.getUsedExtensions().find((name12) => name12 === extensionName);
const extensions = this.json.extensions || {};
return isExtension ? extensions[extensionName] : null;
}
getRequiredExtension(extensionName) {
const isRequired = this.getRequiredExtensions().find((name12) => name12 === extensionName);
return isRequired ? this.getExtension(extensionName) : null;
}
getRequiredExtensions() {
return this.json.extensionsRequired || [];
}
getUsedExtensions() {
return this.json.extensionsUsed || [];
}
getRemovedExtensions() {
return this.json.extensionsRemoved || [];
}
getObjectExtension(object, extensionName) {
const extensions = object.extensions || {};
return extensions[extensionName];
}
getScene(index) {
return this.getObject("scenes", index);
}
getNode(index) {
return this.getObject("nodes", index);
}
getSkin(index) {
return this.getObject("skins", index);
}
getMesh(index) {
return this.getObject("meshes", index);
}
getMaterial(index) {
return this.getObject("materials", index);
}
getAccessor(index) {
return this.getObject("accessors", index);
}
// getCamera(index: number): object | null {
// return null; // TODO: fix thi: object as null;
// }
getTexture(index) {
return this.getObject("textures", index);
}
getSampler(index) {
return this.getObject("samplers", index);
}
getImage(index) {
return this.getObject("images", index);
}
getBufferView(index) {
return this.getObject("bufferViews", index);
}
getBuffer(index) {
return this.getObject("buffers", index);
}
getObject(array, index) {
if (typeof index === "object") {
return index;
}
const object = this.json[array] && this.json[array][index];
if (!object) {
throw new Error(`glTF file error: Could not find ${array}[${index}]`);
}
return object;
}
/**
* Accepts buffer view index or buffer view object
* @returns a `Uint8Array`
*/
getTypedArrayForBufferView(bufferView) {
bufferView = this.getBufferView(bufferView);
const bufferIndex = bufferView.buffer;
const binChunk = this.gltf.buffers[bufferIndex];
assert(binChunk);
const byteOffset = (bufferView.byteOffset || 0) + binChunk.byteOffset;
return new Uint8Array(binChunk.arrayBuffer, byteOffset, bufferView.byteLength);
}
/** Accepts accessor index or accessor object
* @returns a typed array with type that matches the types
*/
getTypedArrayForAccessor(accessor) {
const gltfAccessor = this.getAccessor(accessor);
return getTypedArrayForAccessor(this.gltf.json, this.gltf.buffers, gltfAccessor);
}
/** accepts accessor index or accessor object
* returns a `Uint8Array`
*/
getTypedArrayForImageData(image) {
image = this.getAccessor(image);
const bufferView = this.getBufferView(image.bufferView);
const buffer = this.getBuffer(bufferView.buffer);
const arrayBuffer = buffer.data;
const byteOffset = bufferView.byteOffset || 0;
return new Uint8Array(arrayBuffer, byteOffset, bufferView.byteLength);
}
// MODIFERS
/**
* Add an extra application-defined key to the top-level data structure
*/
addApplicationData(key, data) {
this.json[key] = data;
return this;
}
/**
* `extras` - Standard GLTF field for storing application specific data
*/
addExtraData(key, data) {
this.json.extras = this.json.extras || {};
this.json.extras[key] = data;
return this;
}
addObjectExtension(object, extensionName, data) {
object.extensions = object.extensions || {};
object.extensions[extensionName] = data;
this.registerUsedExtension(extensionName);
return this;
}
setObjectExtension(object, extensionName, data) {
const extensions = object.extensions || {};
extensions[extensionName] = data;
}
removeObjectExtension(object, extensionName) {
const extensions = (object == null ? void 0 : object.extensions) || {};
if (extensions[extensionName]) {
this.json.extensionsRemoved = this.json.extensionsRemoved || [];
const extensionsRemoved = this.json.extensionsRemoved;
if (!extensionsRemoved.includes(extensionName)) {
extensionsRemoved.push(extensionName);
}
}
delete extensions[extensionName];
}
/**
* Add to standard GLTF top level extension object, mark as used
*/
addExtension(extensionName, extensionData = {}) {
assert(extensionData);
this.json.extensions = this.json.extensions || {};
this.json.extensions[extensionName] = extensionData;
this.registerUsedExtension(extensionName);
return extensionData;
}
/**
* Standard GLTF top level extension object, mark as used and required
*/
addRequiredExtension(extensionName, extensionData = {}) {
assert(extensionData);
this.addExtension(extensionName, extensionData);
this.registerRequiredExtension(extensionName);
return extensionData;
}
/**
* Add extensionName to list of used extensions
*/
registerUsedExtension(extensionName) {
this.json.extensionsUsed = this.json.extensionsUsed || [];
if (!this.json.extensionsUsed.find((ext) => ext === extensionName)) {
this.json.extensionsUsed.push(extensionName);
}
}
/**
* Add extensionName to list of required extensions
*/
registerRequiredExtension(extensionName) {
this.registerUsedExtension(extensionName);
this.json.extensionsRequired = this.json.extensionsRequired || [];
if (!this.json.extensionsRequired.find((ext) => ext === extensionName)) {
this.json.extensionsRequired.push(extensionName);
}
}
/**
* Removes an extension from the top-level list
*/
removeExtension(extensionName) {
var _a;
if ((_a = this.json.extensions) == null ? void 0 : _a[extensionName]) {
this.json.extensionsRemoved = this.json.extensionsRemoved || [];
const extensionsRemoved = this.json.extensionsRemoved;
if (!extensionsRemoved.includes(extensionName)) {
extensionsRemoved.push(extensionName);
}
}
if (this.json.extensions) {
delete this.json.extensions[extensionName];
}
if (this.json.extensionsRequired) {
this._removeStringFromArray(this.json.extensionsRequired, extensionName);
}
if (this.json.extensionsUsed) {
this._removeStringFromArray(this.json.extensionsUsed, extensionName);
}
}
/**
* Set default scene which is to be displayed at load time
*/
setDefaultScene(sceneIndex) {
this.json.scene = sceneIndex;
}
/**
* @todo: add more properties for scene initialization:
* name`, `extensions`, `extras`
* https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-scene
*/
addScene(scene) {
const { nodeIndices } = scene;
this.json.scenes = this.json.scenes || [];
this.json.scenes.push({ nodes: nodeIndices });
return this.json.scenes.length - 1;
}
/**
* @todo: add more properties for node initialization:
* `name`, `extensions`, `extras`, `camera`, `children`, `skin`, `rotation`, `scale`, `translation`, `weights`
* https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#node
*/
addNode(node) {
const { meshIndex, matrix } = node;
this.json.nodes = this.json.nodes || [];
const nodeData = { mesh: meshIndex };
if (matrix) {
nodeData.matrix = matrix;
}
this.json.nodes.push(nodeData);
return this.json.nodes.length - 1;
}
/** Adds a mesh to the json part */
addMesh(mesh) {
const { attributes, indices, material, mode = 4 } = mesh;
const accessors = this._addAttributes(attributes);
const glTFMesh = {
primitives: [
{
attributes: accessors,
mode
}
]
};
if (indices) {
const indicesAccessor = this._addIndices(indices);
glTFMesh.primitives[0].indices = indicesAccessor;
}
if (Number.isFinite(material)) {
glTFMesh.primitives[0].material = material;
}
this.json.meshes = this.json.meshes || [];
this.json.meshes.push(glTFMesh);
return this.json.meshes.length - 1;
}
addPointCloud(attributes) {
const accessorIndices = this._addAttributes(attributes);
const glTFMesh = {
primitives: [
{
attributes: accessorIndices,
mode: 0
// GL.POINTS
}
]
};
this.json.meshes = this.json.meshes || [];
this.json.meshes.push(glTFMesh);
return this.json.meshes.length - 1;
}
/**
* Adds a binary image. Builds glTF "JSON metadata" and saves buffer reference
* Buffer will be copied into BIN chunk during "pack"
* Currently encodes as glTF image
* @param imageData
* @param mimeType
*/
addImage(imageData, mimeTypeOpt) {
const metadata = (0, import_images.getBinaryImageMetadata)(imageData);
const mimeType = mimeTypeOpt || (metadata == null ? void 0 : metadata.mimeType);
const bufferViewIndex = this.addBufferView(imageData);
const glTFImage = {
bufferView: bufferViewIndex,
mimeType
};
this.json.images = this.json.images || [];
this.json.images.push(glTFImage);
return this.json.images.length - 1;
}
/**
* Add one untyped source buffer, create a matching glTF `bufferView`, and return its index
* @param buffer
*/
addBufferView(buffer, bufferIndex = 0, byteOffset = this.byteLength) {
const byteLength = buffer.byteLength;
assert(Number.isFinite(byteLength));
this.sourceBuffers = this.sourceBuffers || [];
this.sourceBuffers.push(buffer);
const glTFBufferView = {
buffer: bufferIndex,
// Write offset from the start of the binary body
byteOffset,
byteLength
};
this.byteLength += (0, import_loader_utils.padToNBytes)(byteLength, 4);
this.json.bufferViews = this.json.bufferViews || [];
this.json.bufferViews.push(glTFBufferView);
return this.json.bufferViews.length - 1;
}
/**
* Adds an accessor to a bufferView
* @param bufferViewIndex
* @param accessor
*/
addAccessor(bufferViewIndex, accessor) {
const glTFAccessor = {
bufferView: bufferViewIndex,
// @ts-ignore
type: getAccessorTypeFromSize(accessor.size),
// @ts-ignore
componentType: accessor.componentType,
// @ts-ignore
count: accessor.count,
// @ts-ignore
max: accessor.max,
// @ts-ignore
min: accessor.min
};
this.json.accessors = this.json.accessors || [];
this.json.accessors.push(glTFAccessor);
return this.json.accessors.length - 1;
}
/**
* Add a binary buffer. Builds glTF "JSON metadata" and saves buffer reference
* Buffer will be copied into BIN chunk during "pack"
* Currently encodes buffers as glTF accessors, but this could be optimized
* @param sourceBuffer
* @param accessor
*/
addBinaryBuffer(sourceBuffer, accessor = { size: 3 }) {
const bufferViewIndex = this.addBufferView(sourceBuffer);
let minMax = { min: accessor.min, max: accessor.max };
if (!minMax.min || !minMax.max) {
minMax = this._getAccessorMinMax(sourceBuffer, accessor.size);
}
const accessorDefaults = {
// @ts-ignore
size: accessor.size,
componentType: getComponentTypeFromArray(sourceBuffer),
// @ts-ignore
count: Math.round(sourceBuffer.length / accessor.size),
min: minMax.min,
max: minMax.max
};
return this.addAccessor(bufferViewIndex, Object.assign(accessorDefaults, accessor));
}
/**
* Adds a texture to the json part
* @todo: add more properties for texture initialization
* `sampler`, `name`, `extensions`, `extras`
* https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#texture
*/
addTexture(texture) {
const { imageIndex } = texture;
const glTFTexture = {
source: imageIndex
};
this.json.textures = this.json.textures || [];
this.json.textures.push(glTFTexture);
return this.json.textures.length - 1;
}
/** Adds a material to the json part */
addMaterial(pbrMaterialInfo) {
this.json.materials = this.json.materials || [];
this.json.materials.push(pbrMaterialInfo);
return this.json.materials.length - 1;
}
/** Pack the binary chunk */
createBinaryChunk() {
var _a, _b;
const totalByteLength = this.byteLength;
const arrayBuffer = new ArrayBuffer(totalByteLength);
const targetArray = new Uint8Array(arrayBuffer);
let dstByteOffset = 0;
for (const sourceBuffer of this.sourceBuffers || []) {
dstByteOffset = (0, import_loader_utils.copyToArray)(sourceBuffer, targetArray, dstByteOffset);
}
if ((_b = (_a = this.json) == null ? void 0 : _a.buffers) == null ? void 0 : _b[0]) {
this.json.buffers[0].byteLength = totalByteLength;
} else {
this.json.buffers = [{ byteLength: totalByteLength }];
}
this.gltf.binary = arrayBuffer;
this.sourceBuffers = [arrayBuffer];
this.gltf.buffers = [{ arrayBuffer, byteOffset: 0, byteLength: arrayBuffer.byteLength }];
}
// PRIVATE
_removeStringFromArray(array, string) {
let found = true;
while (found) {
const index = array.indexOf(string);
if (index > -1) {
array.splice(index, 1);
} else {
found = false;
}
}
}
/**
* Add attributes to buffers and create `attributes` object which is part of `mesh`
*/
_addAttributes(attributes = {}) {
const result = {};
for (const attributeKey in attributes) {
const attributeData = attributes[attributeKey];
const attrName = this._getGltfAttributeName(attributeKey);
const accessor = this.addBinaryBuffer(attributeData.value, attributeData);
result[attrName] = accessor;
}
return result;
}
/**
* Add indices to buffers
*/
_addIndices(indices) {
return this.addBinaryBuffer(indices, { size: 1 });
}
/**
* Deduce gltf specific attribue name from input attribute name
*/
_getGltfAttributeName(attributeName) {
switch (attributeName.toLowerCase()) {
case "position":
case "positions":
case "vertices":
return "POSITION";
case "normal":
case "normals":
return "NORMAL";
case "color":
case "colors":
return "COLOR_0";
case "texcoord":
case "texcoords":
return "TEXCOORD_0";
default:
return attributeName;
}
}
/**
* Calculate `min` and `max` arrays of accessor according to spec:
* https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-accessor
*/
_getAccessorMinMax(buffer, size) {
const result = { min: null, max: null };
if (buffer.length < size) {
return result;
}
result.min = [];
result.max = [];
const initValues = buffer.subarray(0, size);
for (const value of initValues) {
result.min.push(value);
result.max.push(value);
}
for (let index = size; index < buffer.length; index += size) {
for (let componentIndex = 0; componentIndex < size; componentIndex++) {
result.min[0 + componentIndex] = Math.min(
// @ts-ignore
result.min[0 + componentIndex],
buffer[index + componentIndex]
);
result.max[0 + componentIndex] = Math.max(
// @ts-ignore
result.max[0 + componentIndex],
buffer[index + componentIndex]
);
}
}
return result;
}
};
// dist/lib/extensions/utils/3d-tiles-utils.js
var import_images2 = require("@loaders.gl/images");
var import_loader_utils2 = require("@loaders.gl/loader-utils");
function emod(n) {
return (n % 1 + 1) % 1;
}
var ATTRIBUTE_TYPE_TO_COMPONENTS2 = {
SCALAR: 1,
VEC2: 2,
VEC3: 3,
VEC4: 4,
MAT2: 4,
MAT3: 9,
MAT4: 16,
BOOLEAN: 1,
STRING: 1,
ENUM: 1
};
var ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY2 = {
INT8: Int8Array,
UINT8: Uint8Array,
INT16: Int16Array,
UINT16: Uint16Array,
INT32: Int32Array,
UINT32: Uint32Array,
INT64: BigInt64Array,
UINT64: BigUint64Array,
FLOAT32: Float32Array,
FLOAT64: Float64Array
};
var ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE2 = {
INT8: 1,
UINT8: 1,
INT16: 2,
UINT16: 2,
INT32: 4,
UINT32: 4,
INT64: 8,
UINT64: 8,
FLOAT32: 4,
FLOAT64: 8
};
function getArrayElementByteSize(attributeType, componentType) {
return ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE2[componentType] * ATTRIBUTE_TYPE_TO_COMPONENTS2[attributeType];
}
function getOffsetsForProperty(scenegraph, bufferViewIndex, offsetType, numberOfElements) {
if (offsetType !== "UINT8" && offsetType !== "UINT16" && offsetType !== "UINT32" && offsetType !== "UINT64") {
return null;
}
const arrayOffsetsBytes = scenegraph.getTypedArrayForBufferView(bufferViewIndex);
const arrayOffsets = convertRawBufferToMetadataArray(
arrayOffsetsBytes,
"SCALAR",
// offsets consist of ONE component
offsetType,
numberOfElements + 1
// The number of offsets is equal to the property table `count` plus one.
);
if (arrayOffsets instanceof BigInt64Array || arrayOffsets instanceof BigUint64Array) {
return null;
}
return arrayOffsets;
}
function convertRawBufferToMetadataArray(data, attributeType, componentType, elementCount = 1) {
const numberOfComponents = ATTRIBUTE_TYPE_TO_COMPONENTS2[attributeType];
const ArrayType = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY2[componentType];
const size = ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE2[componentType];
const length = elementCount * numberOfComponents;
const byteLength = length * size;
let buffer = data.buffer;
let offset = data.byteOffset;
if (offset % size !== 0) {
const bufferArray = new Uint8Array(buffer);
buffer = bufferArray.slice(offset, offset + byteLength).buffer;
offset = 0;
}
return new ArrayType((0, import_loader_utils2.ensureArrayBuffer)(buffer), offset, length);
}
function getPrimitiveTextureData(scenegraph, textureInfo, primitive) {
var _a, _b, _c, _d, _e;
const texCoordAccessorKey = `TEXCOORD_${textureInfo.texCoord || 0}`;
const texCoordAccessorIndex = primitive.attributes[texCoordAccessorKey];
const textureCoordinates = scenegraph.getTypedArrayForAccessor(texCoordAccessorIndex);
const json = scenegraph.gltf.json;
const textureIndex = textureInfo.index;
const imageIndex = (_b = (_a = json.textures) == null ? void 0 : _a[textureIndex]) == null ? void 0 : _b.source;
if (typeof imageIndex !== "undefined") {
const mimeType = (_d = (_c = json.images) == null ? void 0 : _c[imageIndex]) == null ? void 0 : _d.mimeType;
const parsedImage = (_e = scenegraph.gltf.images) == null ? void 0 : _e[imageIndex];
if (parsedImage && typeof parsedImage.width !== "undefined") {
const textureData = [];
for (let index = 0; index < textureCoordinates.length; index += 2) {
const value = getImageValueByCoordinates(parsedImage, mimeType, textureCoordinates, index, textureInfo.channels);
textureData.push(value);
}
return textureData;
}
}
return [];
}
function primitivePropertyDataToAttributes(scenegraph, attributeName, propertyData, featureTable, primitive) {
if (!(propertyData == null ? void 0 : propertyData.length)) {
return;
}
const featureIndices = [];
for (const texelData of propertyData) {
let index = featureTable.findIndex((item) => item === texelData);
if (index === -1) {
index = featureTable.push(texelData) - 1;
}
featureIndices.push(index);
}
const typedArray = new Uint32Array(featureIndices);
const bufferIndex = scenegraph.gltf.buffers.push({
arrayBuffer: typedArray.buffer,
byteOffset: typedArray.byteOffset,
byteLength: typedArray.byteLength
}) - 1;
const bufferViewIndex = scenegraph.addBufferView(typedArray, bufferIndex, 0);
const accessorIndex = scenegraph.addAccessor(bufferViewIndex, {
size: 1,
componentType: getComponentTypeFromArray(typedArray),
count: typedArray.length
});
primitive.attributes[attributeName] = accessorIndex;
}
function getImageValueByCoordinates(parsedImage, mimeType, textureCoordinates, index, channels = [0]) {
const CHANNELS_MAP = {
r: { offset: 0, shift: 0 },
g: { offset: 1, shift: 8 },
b: { offset: 2, shift: 16 },
a: { offset: 3, shift: 24 }
};
const u = textureCoordinates[index];
const v = textureCoordinates[index + 1];
let components = 1;
if (mimeType && (mimeType.indexOf("image/jpeg") !== -1 || mimeType.indexOf("image/png") !== -1))
components = 4;
const offset = coordinatesToOffset(u, v, parsedImage, components);
let value = 0;
for (const c of channels) {
const map = typeof c === "number" ? Object.values(CHANNELS_MAP)[c] : CHANNELS_MAP[c];
const imageOffset = offset + map.offset;
const imageData = (0, import_images2.getImageData)(parsedImage);
if (imageData.data.length <= imageOffset) {
throw new Error(`${imageData.data.length} <= ${imageOffset}`);
}
const imageValue = imageData.data[imageOffset];
value |= imageValue << map.shift;
}
return value;
}
function coordinatesToOffset(u, v, parsedImage, componentsCount = 1) {
const w = parsedImage.width;
const iX = emod(u) * (w - 1);
const indX = Math.round(iX);
const h = parsedImage.height;
const iY = emod(v) * (h - 1);
const indY = Math.round(iY);
const components = parsedImage.components ? parsedImage.components : componentsCount;
const offset = (indY * w + indX) * components;
return offset;
}
function parseVariableLengthArrayNumeric(valuesData, numberOfElements, arrayOffsets, valuesDataBytesLength, valueSize) {
const attributeValueArray = [];
for (let index = 0; index < numberOfElements; index++) {
const arrayOffset = arrayOffsets[index];
const arrayByteSize = arrayOffsets[index + 1] - arrayOffsets[index];
if (arrayByteSize + arrayOffset > valuesDataBytesLength) {
break;
}
const typedArrayOffset = arrayOffset / valueSize;
const elementCount = arrayByteSize / valueSize;
attributeValueArray.push(valuesData.slice(typedArrayOffset, typedArrayOffset + elementCount));
}
return attributeValueArray;
}
function parseFixedLengthArrayNumeric(valuesData, numberOfElements, arrayCount) {
const attributeValueArray = [];
for (let index = 0; index < numberOfElements; index++) {
const elementOffset = index * arrayCount;
attributeValueArray.push(valuesData.slice(elementOffset, elementOffset + arrayCount));
}
return attributeValueArray;
}
function getPropertyDataString(numberOfElements, valuesDataBytes, arrayOffsets, stringOffsets) {
if (arrayOffsets) {
throw new Error("Not implemented - arrayOffsets for strings is specified");
}
if (stringOffsets) {
const stringsArray = [];
const textDecoder = new TextDecoder("utf8");
let stringOffset = 0;
for (let index = 0; index < numberOfElements; index++) {
const stringByteSize = stringOffsets[index + 1] - stringOffsets[index];
if (stringByteSize + stringOffset <= valuesDataBytes.length) {
const stringData = valuesDataBytes.subarray(stringOffset, stringByteSize + stringOffset);
const stringAttribute = textDecoder.decode(stringData);
stringsArray.push(stringAttribute);
stringOffset += stringByteSize;
}
}
return stringsArray;
}
return [];
}
// dist/lib/extensions/EXT_mesh_features.js
var EXT_MESH_FEATURES_NAME = "EXT_mesh_features";
var name = EXT_MESH_FEATURES_NAME;
async function decode(gltfData, options) {
const scenegraph = new GLTFScenegraph(gltfData);
decodeExtMeshFeatures(scenegraph, options);
}
function encode(gltfData, options) {
const scenegraph = new GLTFScenegraph(gltfData);
encodeExtMeshFeatures(scenegraph, options);
scenegraph.createBinaryChunk();
return scenegraph.gltf;
}
function decodeExtMeshFeatures(scenegraph, options) {
const json = scenegraph.gltf.json;
if (!json.meshes) {
return;
}
for (const mesh of json.meshes) {
for (const primitive of mesh.primitives) {
processMeshPrimitiveFeatures(scenegraph, primitive, options);
}
}
}
function processMeshPrimitiveFeatures(scenegraph, primitive, options) {
var _a, _b, _c;
if (!((_a = options == null ? void 0 : options.gltf) == null ? void 0 : _a.loadBuffers)) {
return;
}
const extension = (_b = primitive.extensions) == null ? void 0 : _b[EXT_MESH_FEATURES_NAME];
const featureIds = extension == null ? void 0 : extension.featureIds;
if (!featureIds) {
return;
}
for (const featureId of featureIds) {
let featureIdData;
if (typeof featureId.attribute !== "undefined") {
const accessorKey = `_FEATURE_ID_${featureId.attribute}`;
const accessorIndex = primitive.attributes[accessorKey];
featureIdData = scenegraph.getTypedArrayForAccessor(accessorIndex);
} else if (typeof featureId.texture !== "undefined" && ((_c = options == null ? void 0 : options.gltf) == null ? void 0 : _c.loadImages)) {
featureIdData = getPrimitiveTextureData(scenegraph, featureId.texture, primitive);
} else {
featureIdData = [];
}
featureId.data = featureIdData;
}
}
function encodeExtMeshFeatures(scenegraph, options) {
const meshes = scenegraph.gltf.json.meshes;
if (!meshes) {
return;
}
for (const mesh of meshes) {
for (const primitive of mesh.primitives) {
encodeExtMeshFeaturesForPrimitive(scenegraph, primitive);
}
}
}
function createExtMeshFeatures(scenegraph, primitive, featureIdArray, propertyTableIndex) {
if (!primitive.extensions) {
primitive.extensions = {};
}
let extension = primitive.extensions[EXT_MESH_FEATURES_NAME];
if (!extension) {
extension = { featureIds: [] };
primitive.extensions[EXT_MESH_FEATURES_NAME] = extension;
}
const { featureIds } = extension;
const featureId = {
featureCount: featureIdArray.length,
propertyTable: propertyTableIndex,
data: featureIdArray
};
featureIds.push(featureId);
scenegraph.addObjectExtension(primitive, EXT_MESH_FEATURES_NAME, extension);
}
function encodeExtMeshFeaturesForPrimitive(scenegraph, primitive) {
var _a;
const extension = (_a = primitive.extensions) == null ? void 0 : _a[EXT_MESH_FEATURES_NAME];
if (!extension) {
return;
}
const featureIds = extension.featureIds;
featureIds.forEach((featureId, elementIndex) => {
if (featureId.data) {
const { accessorKey, index } = createAccessorKey(primitive.attributes);
const typedArray = new Uint32Array(featureId.data);
featureIds[elementIndex] = {
featureCount: typedArray.length,
propertyTable: featureId.propertyTable,
attribute: index
};
scenegraph.gltf.buffers.push({
arrayBuffer: typedArray.buffer,
byteOffset: typedArray.byteOffset,
byteLength: typedArray.byteLength
});
const bufferViewIndex = scenegraph.addBufferView(typedArray);
const accessorIndex = scenegraph.addAccessor(bufferViewIndex, {
size: 1,
componentType: getComponentTypeFromArray(typedArray),
count: typedArray.length
});
primitive.attributes[accessorKey] = accessorIndex;
}
});
}
function createAccessorKey(attributes) {
const prefix = "_FEATURE_ID_";
const attrs = Object.keys(attributes).filter((item) => item.indexOf(prefix) === 0);
let max = -1;
for (const a of attrs) {
const n = Number(a.substring(prefix.length));
if (n > max) {
max = n;
}
}
max++;
const accessorKey = `${prefix}${max}`;
return { accessorKey, index: max };
}
// dist/lib/extensions/EXT_structural_metadata.js
var EXT_structural_metadata_exports = {};
__export(EXT_structural_metadata_exports, {
createExtStructuralMetadata: () => createExtStructuralMetadata,
decode: () => decode2,
encode: () => encode2,
name: () => name2
});
var import_loader_utils3 = require("@loaders.gl/loader-utils");
var EXT_STRUCTURAL_METADATA_NAME = "EXT_structural_metadata";
var name2 = EXT_STRUCTURAL_METADATA_NAME;
async function decode2(gltfData, options) {
const scenegraph = new GLTFScenegraph(gltfData);
decodeExtStructuralMetadata(scenegraph, options);
}
function encode2(gltfData, options) {
const scenegraph = new GLTFScenegraph(gltfData);
encodeExtStructuralMetadata(scenegraph, options);
scenegraph.createBinaryChunk();
return scenegraph.gltf;
}
function decodeExtStructuralMetadata(scenegraph, options) {
var _a, _b;
if (!((_a = options.gltf) == null ? void 0 : _a.loadBuffers)) {
return;
}
const extension = scenegraph.getExtension(EXT_STRUCTURAL_METADATA_NAME);
if (!extension) {
return;
}
if ((_b = options.gltf) == null ? void 0 : _b.loadImages) {
decodePropertyTextures(scenegraph, extension);
}
decodePropertyTables(scenegraph, extension);
}
function decodePropertyTextures(scenegraph, extension) {
const propertyTextures = extension.propertyTextures;
const json = scenegraph.gltf.json;
if (propertyTextures && json.meshes) {
for (const mesh of json.meshes) {
for (const primitive of mesh.primitives) {
processPrimitivePropertyTextures(scenegraph, propertyTextures, primitive, extension);
}
}
}
}
function decodePropertyTables(scenegraph, extension) {
const schema = extension.schema;
if (!schema) {
return;
}
const schemaClasses = schema.classes;
const propertyTables = extension.propertyTables;
if (schemaClasses && propertyTables) {
for (const schemaName in schemaClasses) {
const propertyTable = findPropertyTableByClass(propertyTables, schemaName);
if (propertyTable) {
processPropertyTable(scenegraph, schema, propertyTable);
}
}
}
}
function findPropertyTableByClass(propertyTables, schemaClassName) {
for (const propertyTable of propertyTables) {
if (propertyTable.class === schemaClassName) {
return propertyTable;
}
}
return null;
}
function processPrimitivePropertyTextures(scenegraph, propertyTextures, primitive, extension) {
var _a;
if (!propertyTextures) {
return;
}
const primitiveExtension = (_a = primitive.extensions) == null ? void 0 : _a[EXT_STRUCTURAL_METADATA_NAME];
const primitivePropertyTextureIndices = primitiveExtension == null ? void 0 : primitiveExtension.propertyTextures;
if (!primitivePropertyTextureIndices) {
return;
}
for (const primitivePropertyTextureIndex of primitivePropertyTextureIndices) {
const propertyTexture = propertyTextures[primitivePropertyTextureIndex];
processPrimitivePropertyTexture(scenegraph, propertyTexture, primitive, extension);
}
}
function processPrimitivePropertyTexture(scenegraph, propertyTexture, primitive, extension) {
var _a;
if (!propertyTexture.properties) {
return;
}
if (!extension.dataAttributeNames) {
extension.dataAttributeNames = [];
}
const className = propertyTexture.class;
for (const propertyName in propertyTexture.properties) {
const attributeName = `${className}_${propertyName}`;
const textureInfoTopLevel = (_a = propertyTexture.properties) == null ? void 0 : _a[propertyName];
if (!textureInfoTopLevel) {
continue;
}
if (!textureInfoTopLevel.data) {
textureInfoTopLevel.data = [];
}
const featureTextureTable = textureInfoTopLevel.data;
const propertyData = getPrimitiveTextureData(scenegraph, textureInfoTopLevel, primitive);
if (propertyData === null) {
continue;
}
primitivePropertyDataToAttributes(scenegraph, attributeName, propertyData, featureTextureTable, primitive);
textureInfoTopLevel.data = featureTextureTable;
extension.dataAttributeNames.push(attributeName);
}
}
function processPropertyTable(scenegraph, schema, propertyTable) {
var _a, _b;
const schemaClass = (_a = schema.classes) == null ? void 0 : _a[propertyTable.class];
if (!schemaClass) {
throw new Error(`Incorrect data in the EXT_structural_metadata extension: no schema class with name ${propertyTable.class}`);
}
const numberOfElements = propertyTable.count;
for (const propertyName in schemaClass.properties) {
const classProperty = schemaClass.properties[propertyName];
const propertyTableProperty = (_b = propertyTable.properties) == null ? void 0 : _b[propertyName];
if (propertyTableProperty) {
const data = getPropertyDataFromBinarySource(scenegraph, schema, classProperty, numberOfElements, propertyTableProperty);
propertyTableProperty.data = data;
}
}
}
function getPropertyDataFromBinarySource(scenegraph, schema, classProperty, numberOfElements, propertyTableProperty) {
let data = [];
const valuesBufferView = propertyTableProperty.values;
const valuesDataBytes = scenegraph.getTypedArrayForBufferView(valuesBufferView);
const arrayOffsets = getArrayOffsetsForProperty(scenegraph, classProperty, propertyTableProperty, numberOfElements);
const stringOffsets = getStringOffsetsForProperty(scenegraph, propertyTableProperty, numberOfElements);
switch (classProperty.type) {
case "SCALAR":
case "VEC2":
case "VEC3":
case "VEC4":
case "MAT2":
case "MAT3":
case "MAT4": {
data = getPropertyDataNumeric(classProperty, numberOfElements, valuesDataBytes, arrayOffsets);
break;
}
case "BOOLEAN": {
throw new Error(`Not implemented - classProperty.type=${classProperty.type}`);
}
case "STRING": {
data = getPropertyDataString(numberOfElements, valuesDataBytes, arrayOffsets, stringOffsets);
break;
}
case "ENUM": {
data = getPropertyDataENUM(schema, classProperty, numberOfElements, valuesDataBytes, arrayOffsets);
break;
}
default:
throw new Error(`Unknown classProperty type ${classProperty.type}`);
}
return data;
}
function getArrayOffsetsForProperty(scenegraph, classProperty, propertyTableProperty, numberOfElements) {
if (classProperty.array && // `count` is a number of array elements. May only be defined when `array` is true.
// If `count` is NOT defined, it's a VARIABLE-length array
typeof classProperty.count === "undefined" && // `arrayOffsets` is an index of the buffer view containing offsets for variable-length arrays.
typeof propertyTableProperty.arrayOffsets !== "undefined") {
return getOffsetsForProperty(scenegraph, propertyTableProperty.arrayOffsets, propertyTableProperty.arrayOffsetType || "UINT32", numberOfElements);
}
return null;
}
function getStringOffsetsForProperty(scenegraph, propertyTableProperty, numberOfElements) {
if (typeof propertyTableProperty.stringOffsets !== "undefined") {
return getOffsetsForProperty(scenegraph, propertyTableProperty.stringOffsets, propertyTableProperty.stringOffsetType || "UINT32", numberOfElements);
}
return null;
}
function getPropertyDataNumeric(classProperty, numberOfElements, valuesDataBytes, arrayOffsets) {
const isArray = classProperty.array;
const arrayCount = classProperty.count;
const elementSize = getArrayElementByteSize(classProperty.type, classProperty.componentType);
const elementCount = valuesDataBytes.byteLength / elementSize;
let valuesData;
if (classProperty.componentType) {
valuesData = convertRawBufferToMetadataArray(
valuesDataBytes,
classProperty.type,
// The datatype of the element's components. Only applicable to `SCALAR`, `VECN`, and `MATN` types.
classProperty.componentType,
elementCount
);
} else {
valuesData = valuesDataBytes;
}
if (isArray) {
if (arrayOffsets) {
return parseVariableLengthArrayNumeric(valuesData, numberOfElements, arrayOffsets, valuesDataBytes.length, elementSize);
}
if (arrayCount) {
return parseFixedLengthArrayNumeric(valuesData, numberOfElements, arrayCount);
}
return [];
}
return valuesData;
}
function getPropertyDataENUM(schema, classProperty, numberOfElements, valuesDataBytes, arrayOffsets) {
var _a;
const enumType = classProperty.enumType;
if (!enumType) {
throw new Error("Incorrect data in the EXT_structural_metadata extension: classProperty.enumType is not set for type ENUM");
}
const enumEntry = (_a = schema.enums) == null ? void 0 : _a[enumType];
if (!enumEntry) {
throw new Error(`Incorrect data in the EXT_structural_metadata extension: schema.enums does't contain ${enumType}`);
}
const enumValueType = enumEntry.valueType || "UINT16";
const elementSize = getArrayElementByteSize(classProperty.type, enumValueType);
const elementCount = valuesDataBytes.byteLength / elementSize;
let valuesData = convertRawBufferToMetadataArray(valuesDataBytes, classProperty.type, enumValueType, elementCount);
if (!valuesData) {
valuesData = valuesDataBytes;
}
if (classProperty.array) {
if (arrayOffsets) {
return parseVariableLengthArrayENUM({
valuesData,
numberOfElements,
arrayOffsets,
valuesDataBytesLength: valuesDataBytes.length,
elementSize,
enumEntry
});
}
const arrayCount = classProperty.count;
if (arrayCount) {
return parseFixedLengthArrayENUM(valuesData, numberOfElements, arrayCount, enumEntry);
}
return [];
}
return getEnumsArray(valuesData, 0, numberOfElements, enumEntry);
}
function parseVariableLengthArrayENUM(params) {
const { valuesData, numberOfElements, arrayOffsets, valuesDataBytesLength, elementSize, enumEntry } = params;
const attributeValueArray = [];
for (let index = 0; index < numberOfElements; index++) {
const arrayOffset = arrayOffsets[index];
const arrayByteSize = arrayOffsets[index + 1] - arrayOffsets[index];
if (arrayByteSize + arrayOffset > valuesDataBytesLength) {
break;
}
const typedArrayOffset = arrayOffset / elementSize;
const elementCount = arrayByteSize / elementSize;
const array = getEnumsArray(valuesData, typedArrayOffset, elementCount, enumEntry);
attributeValueArray.push(array);
}
return attributeValueArray;
}
function parseFixedLengthArrayENUM(valuesData, numberOfElements, arrayCount, enumEntry) {
const attributeValueArray = [];
for (let index = 0; index < numberOfElements; index++) {
const elementOffset = arrayCount * index;
const array = getEnumsArray(valuesData, elementOffset, arrayCount, enumEntry);
attributeValueArray.push(array);
}
return attributeValueArray;
}
function getEnumsArray(valuesData, offset, count, enumEntry) {
const array = [];
for (let i = 0; i < count; i++) {
if (valuesData instanceof BigInt64Array || valuesData instanceof BigUint64Array) {
array.push("");
} else {
const value = valuesData[offset + i];
const enumObject = getEnumByValue(enumEntry, value);
if (enumObject) {
array.push(enumObject.name);
} else {
array.push("");
}
}
}
return array;
}
function getEnumByValue(enumEntry, value) {
for (const enumValue of enumEntry.values) {
if (enumValue.value === value) {
return enumValue;
}
}
return null;
}
var SCHEMA_CLASS_ID_DEFAULT = "schemaClassId";
function encodeExtStructuralMetadata(scenegraph, options) {
var _a, _b;
const extension = scenegraph.getExtension(EXT_STRUCTURAL_METADATA_NAME);
if (!extension) {
return;
}
if (extension.propertyTables) {
for (const table of extension.propertyTables) {
const classId = table.class;
const schemaClass = (_b = (_a = extension.schema) == null ? void 0 : _a.classes) == null ? void 0 : _b[classId];
if (table.properties && schemaClass) {
encodeProperties(table, schemaClass, scenegraph);
}
}
}
}
function encodeProperties(table, schemaClass, scenegraph) {
for (const propertyName in table.properties) {
const data = table.properties[propertyName].data;
if (data) {
const classProperty = schemaClass.properties[propertyName];
if (classProperty) {
const tableProperty = createPropertyTableProperty(data, classProperty, scenegraph);
table.properties[propertyName] = tableProperty;
}
}
}
}
function createExtStructuralMetadata(scenegraph, propertyAttributes, classId = SCHEMA_CLASS_ID_DEFAULT) {
let extension = scenegraph.getExtension(EXT_STRUCTURAL_METADATA_NAME);
if (!extension) {
extension = scenegraph.addExtension(EXT_STRUCTURAL_METADATA_NAME);
}
extension.schema = createSchema(propertyAttributes, classId, extension.schema);
const table = createPropertyTable(propertyAttributes, classId, extension.schema);
if (!extension.propertyTables) {
extension.propertyTables = [];
}
return extension.propertyTables.push(table) - 1;
}
function createSchema(propertyAttributes, classId, schemaToUpdate) {
const schema = schemaToUpdate ?? {
id: "schema_id"
};
const schemaClass = {
properties: {}
};
for (const attribute of propertyAttributes) {
const classProperty = {
type: attribute.elementType,
componentType: attribute.componentType
};
schemaClass.properties[attribute.name] = classProperty;
}
schema.classes = {};
schema.classes[classId] = schemaClass;
return schema;
}
function createPropertyTable(propertyAttributes, classId, schema) {
var _a;
const table = {
class: classId,
count: 0
};
let count = 0;
const schemaClass = (_a = schema.classes) == null ? void 0 : _a[classId];
for (const attribute of propertyAttributes) {
if (count === 0) {
count = attribute.values.length;
}
if (count !== attribute.values.length && attribute.values.length) {
throw new Error("Illegal values in attributes");
}
const classProperty = schemaClass == null ? void 0 : schemaClass.properties[attribute.name];
if (classProperty) {
if (!table.properties) {
table.properties = {};
}
table.properties[attribute.name] = { values: 0, data: attribute.values };
}
}
table.count = count;
return table;
}
function createPropertyTableProperty(values, classProperty, scenegraph) {
const prop = { values: 0 };
if