智慧水务管理系统 - 精河县供水工程综合管理平台

GltfStructuralMetadataLoader.js 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. import Check from "../Core/Check.js";
  2. import Frozen from "../Core/Frozen.js";
  3. import defined from "../Core/defined.js";
  4. import DeveloperError from "../Core/DeveloperError.js";
  5. import parseStructuralMetadata from "./parseStructuralMetadata.js";
  6. import parseFeatureMetadataLegacy from "./parseFeatureMetadataLegacy.js";
  7. import ResourceCache from "./ResourceCache.js";
  8. import ResourceLoader from "./ResourceLoader.js";
  9. import ResourceLoaderState from "./ResourceLoaderState.js";
  10. /**
  11. * Loads glTF structural metadata
  12. * <p>
  13. * Implements the {@link ResourceLoader} interface.
  14. * </p>
  15. *
  16. * @private
  17. * @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.
  18. */
  19. class GltfStructuralMetadataLoader extends ResourceLoader {
  20. /**
  21. * @param {object} options Object with the following properties:
  22. * @param {object} options.gltf The glTF JSON.
  23. * @param {string} [options.extension] The <code>EXT_structural_metadata</code> extension object. If this is undefined, then extensionLegacy must be defined.
  24. * @param {string} [options.extensionLegacy] The legacy <code>EXT_feature_metadata</code> extension for backwards compatibility.
  25. * @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
  26. * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
  27. * @param {SupportedImageFormats} options.supportedImageFormats The supported image formats.
  28. * @param {FrameState} options.frameState The frame state.
  29. * @param {string} [options.cacheKey] The cache key of the resource.
  30. * @param {boolean} [options.asynchronous=true] Determines if WebGL resource creation will be spread out over several frames or block until all WebGL resources are created.
  31. */
  32. constructor(options) {
  33. super();
  34. options = options ?? Frozen.EMPTY_OBJECT;
  35. const {
  36. gltf,
  37. extension,
  38. extensionLegacy,
  39. gltfResource,
  40. baseResource,
  41. supportedImageFormats,
  42. frameState,
  43. cacheKey,
  44. asynchronous = true,
  45. } = options;
  46. //>>includeStart('debug', pragmas.debug);
  47. Check.typeOf.object("options.gltf", gltf);
  48. Check.typeOf.object("options.gltfResource", gltfResource);
  49. Check.typeOf.object("options.baseResource", baseResource);
  50. Check.typeOf.object("options.supportedImageFormats", supportedImageFormats);
  51. Check.typeOf.object("options.frameState", frameState);
  52. if (!defined(options.extension) && !defined(options.extensionLegacy)) {
  53. throw new DeveloperError(
  54. "One of options.extension or options.extensionLegacy must be specified",
  55. );
  56. }
  57. //>>includeEnd('debug');
  58. this._gltfResource = gltfResource;
  59. this._baseResource = baseResource;
  60. this._gltf = gltf;
  61. this._extension = extension;
  62. this._extensionLegacy = extensionLegacy;
  63. this._supportedImageFormats = supportedImageFormats;
  64. this._frameState = frameState;
  65. this._cacheKey = cacheKey;
  66. this._asynchronous = asynchronous;
  67. this._bufferViewLoaders = [];
  68. this._bufferViewIds = [];
  69. this._textureLoaders = [];
  70. this._textureIds = [];
  71. this._schemaLoader = undefined;
  72. this._structuralMetadata = undefined;
  73. this._state = ResourceLoaderState.UNLOADED;
  74. this._promise = undefined;
  75. }
  76. /**
  77. * The cache key of the resource.
  78. *
  79. *
  80. * @type {string}
  81. * @readonly
  82. * @private
  83. */
  84. get cacheKey() {
  85. return this._cacheKey;
  86. }
  87. /**
  88. * The parsed structural metadata
  89. *
  90. *
  91. * @type {StructuralMetadata}
  92. * @readonly
  93. * @private
  94. */
  95. get structuralMetadata() {
  96. return this._structuralMetadata;
  97. }
  98. /**
  99. * Loads the resource.
  100. * @returns {Promise<GltfStructuralMetadataLoader>} A promise which resolves to the loader when the resource loading is completed.
  101. * @private
  102. */
  103. load() {
  104. if (defined(this._promise)) {
  105. return this._promise;
  106. }
  107. this._state = ResourceLoaderState.LOADING;
  108. this._promise = loadResources(this);
  109. return this._promise;
  110. }
  111. /**
  112. * Processes the resource until it becomes ready.
  113. *
  114. * @param {FrameState} frameState The frame state.
  115. * @private
  116. */
  117. process(frameState) {
  118. //>>includeStart('debug', pragmas.debug);
  119. Check.typeOf.object("frameState", frameState);
  120. //>>includeEnd('debug');
  121. if (this._state === ResourceLoaderState.READY) {
  122. return true;
  123. }
  124. if (this._state !== ResourceLoaderState.LOADED) {
  125. return false;
  126. }
  127. const textureLoaders = this._textureLoaders;
  128. const textureLoadersLength = textureLoaders.length;
  129. let ready = true;
  130. for (let i = 0; i < textureLoadersLength; ++i) {
  131. const textureLoader = textureLoaders[i];
  132. const textureReady = textureLoader.process(frameState);
  133. ready = ready && textureReady;
  134. }
  135. if (!ready) {
  136. return false;
  137. }
  138. const schema = this._schemaLoader.schema;
  139. const bufferViews = {};
  140. for (let i = 0; i < this._bufferViewIds.length; ++i) {
  141. const bufferViewId = this._bufferViewIds[i];
  142. const bufferViewLoader = this._bufferViewLoaders[i];
  143. if (!bufferViewLoader.isDestroyed()) {
  144. // Copy the typed array and let the underlying ArrayBuffer be freed
  145. const bufferViewTypedArray = new Uint8Array(
  146. bufferViewLoader.typedArray,
  147. );
  148. bufferViews[bufferViewId] = bufferViewTypedArray;
  149. }
  150. }
  151. const textures = {};
  152. for (let i = 0; i < this._textureIds.length; ++i) {
  153. const textureId = this._textureIds[i];
  154. const textureLoader = textureLoaders[i];
  155. if (!textureLoader.isDestroyed()) {
  156. textures[textureId] = textureLoader.texture;
  157. }
  158. }
  159. if (defined(this._extension)) {
  160. this._structuralMetadata = parseStructuralMetadata({
  161. extension: this._extension,
  162. schema: schema,
  163. bufferViews: bufferViews,
  164. textures: textures,
  165. context: frameState.context,
  166. });
  167. } else {
  168. this._structuralMetadata = parseFeatureMetadataLegacy({
  169. extension: this._extensionLegacy,
  170. schema: schema,
  171. bufferViews: bufferViews,
  172. textures: textures,
  173. });
  174. }
  175. // Buffer views can be unloaded after the data has been copied
  176. unloadBufferViews(this);
  177. this._state = ResourceLoaderState.READY;
  178. return true;
  179. }
  180. /**
  181. * Unloads the resource.
  182. * @private
  183. */
  184. unload() {
  185. unloadBufferViews(this);
  186. unloadTextures(this);
  187. if (defined(this._schemaLoader)) {
  188. ResourceCache.unload(this._schemaLoader);
  189. }
  190. this._schemaLoader = undefined;
  191. if (defined(this._structuralMetadata)) {
  192. this._structuralMetadata.destroy();
  193. }
  194. this._structuralMetadata = undefined;
  195. }
  196. }
  197. async function loadResources(loader) {
  198. try {
  199. const bufferViewsPromise = loadBufferViews(loader);
  200. const texturesPromise = loadTextures(loader);
  201. const schemaPromise = loadSchema(loader);
  202. await Promise.all([bufferViewsPromise, texturesPromise, schemaPromise]);
  203. if (loader.isDestroyed()) {
  204. return;
  205. }
  206. loader._gltf = undefined; // No longer need to hold onto the glTF
  207. loader._state = ResourceLoaderState.LOADED;
  208. return loader;
  209. } catch (error) {
  210. if (loader.isDestroyed()) {
  211. return;
  212. }
  213. loader.unload();
  214. loader._state = ResourceLoaderState.FAILED;
  215. const errorMessage = "Failed to load structural metadata";
  216. throw loader.getError(errorMessage, error);
  217. }
  218. }
  219. function gatherBufferViewIdsFromProperties(properties, bufferViewIdSet) {
  220. for (const propertyId in properties) {
  221. if (properties.hasOwnProperty(propertyId)) {
  222. const property = properties[propertyId];
  223. const values = property.values;
  224. const arrayOffsets = property.arrayOffsets;
  225. const stringOffsets = property.stringOffsets;
  226. // Using an object like a mathematical set
  227. if (defined(values)) {
  228. bufferViewIdSet[values] = true;
  229. }
  230. if (defined(arrayOffsets)) {
  231. bufferViewIdSet[arrayOffsets] = true;
  232. }
  233. if (defined(stringOffsets)) {
  234. bufferViewIdSet[stringOffsets] = true;
  235. }
  236. }
  237. }
  238. }
  239. function gatherBufferViewIdsFromPropertiesLegacy(properties, bufferViewIdSet) {
  240. for (const propertyId in properties) {
  241. if (properties.hasOwnProperty(propertyId)) {
  242. const property = properties[propertyId];
  243. const bufferView = property.bufferView;
  244. const arrayOffsetBufferView = property.arrayOffsetBufferView;
  245. const stringOffsetBufferView = property.stringOffsetBufferView;
  246. // Using an object like a mathematical set
  247. if (defined(bufferView)) {
  248. bufferViewIdSet[bufferView] = true;
  249. }
  250. if (defined(arrayOffsetBufferView)) {
  251. bufferViewIdSet[arrayOffsetBufferView] = true;
  252. }
  253. if (defined(stringOffsetBufferView)) {
  254. bufferViewIdSet[stringOffsetBufferView] = true;
  255. }
  256. }
  257. }
  258. }
  259. function gatherUsedBufferViewIds(extension) {
  260. const propertyTables = extension.propertyTables;
  261. const bufferViewIdSet = {};
  262. if (defined(propertyTables)) {
  263. for (let i = 0; i < propertyTables.length; i++) {
  264. const propertyTable = propertyTables[i];
  265. gatherBufferViewIdsFromProperties(
  266. propertyTable.properties,
  267. bufferViewIdSet,
  268. );
  269. }
  270. }
  271. return bufferViewIdSet;
  272. }
  273. function gatherUsedBufferViewIdsLegacy(extensionLegacy) {
  274. const featureTables = extensionLegacy.featureTables;
  275. const bufferViewIdSet = {};
  276. if (defined(featureTables)) {
  277. for (const featureTableId in featureTables) {
  278. if (featureTables.hasOwnProperty(featureTableId)) {
  279. const featureTable = featureTables[featureTableId];
  280. const properties = featureTable.properties;
  281. if (defined(properties)) {
  282. gatherBufferViewIdsFromPropertiesLegacy(properties, bufferViewIdSet);
  283. }
  284. }
  285. }
  286. }
  287. return bufferViewIdSet;
  288. }
  289. async function loadBufferViews(structuralMetadataLoader) {
  290. let bufferViewIds;
  291. if (defined(structuralMetadataLoader._extension)) {
  292. bufferViewIds = gatherUsedBufferViewIds(
  293. structuralMetadataLoader._extension,
  294. );
  295. } else {
  296. bufferViewIds = gatherUsedBufferViewIdsLegacy(
  297. structuralMetadataLoader._extensionLegacy,
  298. );
  299. }
  300. // Load the buffer views
  301. const bufferViewPromises = [];
  302. for (const bufferViewId in bufferViewIds) {
  303. if (bufferViewIds.hasOwnProperty(bufferViewId)) {
  304. const bufferViewLoader = ResourceCache.getBufferViewLoader({
  305. gltf: structuralMetadataLoader._gltf,
  306. bufferViewId: parseInt(bufferViewId),
  307. gltfResource: structuralMetadataLoader._gltfResource,
  308. baseResource: structuralMetadataLoader._baseResource,
  309. });
  310. structuralMetadataLoader._bufferViewLoaders.push(bufferViewLoader);
  311. structuralMetadataLoader._bufferViewIds.push(bufferViewId);
  312. bufferViewPromises.push(bufferViewLoader.load());
  313. }
  314. }
  315. return Promise.all(bufferViewPromises);
  316. }
  317. function gatherUsedTextureIds(structuralMetadataExtension) {
  318. // Gather the used textures
  319. const textureIds = {};
  320. const propertyTextures = structuralMetadataExtension.propertyTextures;
  321. if (defined(propertyTextures)) {
  322. for (let i = 0; i < propertyTextures.length; i++) {
  323. const propertyTexture = propertyTextures[i];
  324. const properties = propertyTexture.properties;
  325. if (defined(properties)) {
  326. gatherTextureIdsFromProperties(properties, textureIds);
  327. }
  328. }
  329. }
  330. return textureIds;
  331. }
  332. function gatherTextureIdsFromProperties(properties, textureIds) {
  333. for (const propertyId in properties) {
  334. if (properties.hasOwnProperty(propertyId)) {
  335. // in EXT_structural_metadata the property is a valid textureInfo.
  336. const textureInfo = properties[propertyId];
  337. textureIds[textureInfo.index] = textureInfo;
  338. }
  339. }
  340. }
  341. function gatherUsedTextureIdsLegacy(extensionLegacy) {
  342. // Gather the used textures
  343. const textureIds = {};
  344. const featureTextures = extensionLegacy.featureTextures;
  345. if (defined(featureTextures)) {
  346. for (const featureTextureId in featureTextures) {
  347. if (featureTextures.hasOwnProperty(featureTextureId)) {
  348. const featureTexture = featureTextures[featureTextureId];
  349. const properties = featureTexture.properties;
  350. if (defined(properties)) {
  351. gatherTextureIdsFromPropertiesLegacy(properties, textureIds);
  352. }
  353. }
  354. }
  355. }
  356. return textureIds;
  357. }
  358. function gatherTextureIdsFromPropertiesLegacy(properties, textureIds) {
  359. for (const propertyId in properties) {
  360. if (properties.hasOwnProperty(propertyId)) {
  361. const property = properties[propertyId];
  362. const textureInfo = property.texture;
  363. textureIds[textureInfo.index] = textureInfo;
  364. }
  365. }
  366. }
  367. function loadTextures(structuralMetadataLoader) {
  368. let textureIds;
  369. if (defined(structuralMetadataLoader._extension)) {
  370. textureIds = gatherUsedTextureIds(structuralMetadataLoader._extension);
  371. } else {
  372. textureIds = gatherUsedTextureIdsLegacy(
  373. structuralMetadataLoader._extensionLegacy,
  374. );
  375. }
  376. const gltf = structuralMetadataLoader._gltf;
  377. const gltfResource = structuralMetadataLoader._gltfResource;
  378. const baseResource = structuralMetadataLoader._baseResource;
  379. const supportedImageFormats = structuralMetadataLoader._supportedImageFormats;
  380. const frameState = structuralMetadataLoader._frameState;
  381. const asynchronous = structuralMetadataLoader._asynchronous;
  382. // Load the textures
  383. const texturePromises = [];
  384. for (const textureId in textureIds) {
  385. if (textureIds.hasOwnProperty(textureId)) {
  386. const textureLoader = ResourceCache.getTextureLoader({
  387. gltf: gltf,
  388. textureInfo: textureIds[textureId],
  389. gltfResource: gltfResource,
  390. baseResource: baseResource,
  391. supportedImageFormats: supportedImageFormats,
  392. frameState: frameState,
  393. asynchronous: asynchronous,
  394. });
  395. structuralMetadataLoader._textureLoaders.push(textureLoader);
  396. structuralMetadataLoader._textureIds.push(textureId);
  397. texturePromises.push(textureLoader.load());
  398. }
  399. }
  400. return Promise.all(texturePromises);
  401. }
  402. async function loadSchema(structuralMetadataLoader) {
  403. const extension =
  404. structuralMetadataLoader._extension ??
  405. structuralMetadataLoader._extensionLegacy;
  406. let schemaLoader;
  407. if (defined(extension.schemaUri)) {
  408. const resource = structuralMetadataLoader._baseResource.getDerivedResource({
  409. url: extension.schemaUri,
  410. });
  411. schemaLoader = ResourceCache.getSchemaLoader({
  412. resource: resource,
  413. });
  414. } else {
  415. schemaLoader = ResourceCache.getSchemaLoader({
  416. schema: extension.schema,
  417. });
  418. }
  419. structuralMetadataLoader._schemaLoader = schemaLoader;
  420. await schemaLoader.load();
  421. if (!schemaLoader.isDestroyed()) {
  422. return schemaLoader.schema;
  423. }
  424. }
  425. function unloadBufferViews(structuralMetadataLoader) {
  426. const bufferViewLoaders = structuralMetadataLoader._bufferViewLoaders;
  427. const bufferViewLoadersLength = bufferViewLoaders.length;
  428. for (let i = 0; i < bufferViewLoadersLength; ++i) {
  429. ResourceCache.unload(bufferViewLoaders[i]);
  430. }
  431. structuralMetadataLoader._bufferViewLoaders.length = 0;
  432. structuralMetadataLoader._bufferViewIds.length = 0;
  433. }
  434. function unloadTextures(structuralMetadataLoader) {
  435. const textureLoaders = structuralMetadataLoader._textureLoaders;
  436. const textureLoadersLength = textureLoaders.length;
  437. for (let i = 0; i < textureLoadersLength; ++i) {
  438. ResourceCache.unload(textureLoaders[i]);
  439. }
  440. structuralMetadataLoader._textureLoaders.length = 0;
  441. structuralMetadataLoader._textureIds.length = 0;
  442. }
  443. export default GltfStructuralMetadataLoader;