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("");
}