import Check from "../Core/Check.js"; import clone from "../Core/clone.js"; import defaultValue from "../Core/defaultValue.js"; import defined from "../Core/defined.js"; import PropertyTable from "./PropertyTable.js"; import PropertyTexture from "./PropertyTexture.js"; import FeatureMetadata from "./FeatureMetadata.js"; import MetadataTable from "./MetadataTable.js"; /** * Parse the EXT_mesh_features glTF extension to create a * feature metadata object. * * @param {Object} options Object with the following properties: * @param {Object} options.extension The extension JSON object. * @param {MetadataSchema} options.schema The parsed schema. * @param {Object.} [options.bufferViews] An object mapping bufferView IDs to Uint8Array objects. * @param {Object.} [options.textures] An object mapping texture IDs to {@link Texture} objects. * @return {FeatureMetadata} A feature metadata object * @private * @experimental This feature is using part of the 3D Tiles spec that is not final and is subject to change without Cesium's standard deprecation policy. */ export default function parseFeatureMetadata(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); var extension = options.extension; // The calling code is responsible for loading the schema. // This keeps metadata parsing synchronous. var schema = options.schema; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.extension", extension); Check.typeOf.object("options.schema", schema); //>>includeEnd('debug'); var i; var propertyTables = []; if (defined(extension.propertyTables)) { for (i = 0; i < extension.propertyTables.length; i++) { var propertyTable = extension.propertyTables[i]; var classDefinition = schema.classes[propertyTable.class]; var metadataTable = new MetadataTable({ count: propertyTable.count, properties: propertyTable.properties, class: classDefinition, bufferViews: options.bufferViews, }); propertyTables.push( new PropertyTable({ id: i, name: propertyTable.name, count: propertyTable.count, metadataTable: metadataTable, extras: propertyTable.extras, extensions: propertyTable.extensions, }) ); } } var propertyTextures = []; if (defined(extension.propertyTextures)) { for (i = 0; i < extension.propertyTextures.length; i++) { var propertyTexture = extension.propertyTextures[i]; propertyTextures.push( new PropertyTexture({ id: i, name: propertyTexture.name, featureTexture: reformatPropertyTexture(propertyTexture), class: schema.classes[propertyTexture.class], textures: options.textures, }) ); } } return new FeatureMetadata({ schema: schema, propertyTables: propertyTables, propertyTextures: propertyTextures, statistics: extension.statistics, extras: extension.extras, extensions: extension.extensions, }); } /** * The legacy EXT_feature_metadata schema was a bit broad in what it could do. * The properties in a feature texture could potentially belong to different * textures. For full backwards compatibility, here we transcode backwards * from EXT_mesh_features to EXT_feature_metadata. * * @param {Object} propertyTexture The property texture JSON from EXT_mesh_features * @return {Object} The corresponding feature texture JSON for the legacy EXT_feature_metadata * @private */ function reformatPropertyTexture(propertyTexture) { // in EXT_mesh_features propertyTexture is a valid glTF textureInfo // since it has an index and a texCoord. var textureInfo = clone(propertyTexture); var featureTexture = clone(propertyTexture); featureTexture.properties = {}; var originalProperties = propertyTexture.properties; for (var propertyId in originalProperties) { if (originalProperties.hasOwnProperty(propertyId)) { var channels = originalProperties[propertyId]; featureTexture.properties[propertyId] = { texture: textureInfo, channels: reformatChannels(channels), }; } } return featureTexture; } /** * Reformat from an array of channel indices like [0, 1] to a * string of channels as would be used in GLSL swizzling (e.g. "rg") * * @param {Number[]} channels the channel indices * @return {String} The channels as a string of "r", "g", "b" or "a" characters. * @private */ function reformatChannels(channels) { return channels .map(function (channelIndex) { return "rgba".charAt(channelIndex); }) .join(""); }