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

ResourceCacheKey.js 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  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 getAbsoluteUri from "../Core/getAbsoluteUri.js";
  6. import GltfLoaderUtil from "./GltfLoaderUtil.js";
  7. import hasExtension from "./hasExtension.js";
  8. /**
  9. * Compute cache keys for resources in {@link ResourceCache}.
  10. *
  11. * @namespace ResourceCacheKey
  12. *
  13. * @private
  14. */
  15. const ResourceCacheKey = {};
  16. function getExternalResourceCacheKey(resource) {
  17. return getAbsoluteUri(resource.url);
  18. }
  19. function getBufferViewCacheKey(bufferView) {
  20. let { byteOffset, byteLength } = bufferView;
  21. if (hasExtension(bufferView, "EXT_meshopt_compression")) {
  22. const meshopt = bufferView.extensions.EXT_meshopt_compression;
  23. byteOffset = meshopt.byteOffset ?? 0;
  24. byteLength = meshopt.byteLength;
  25. }
  26. return `${byteOffset}-${byteOffset + byteLength}`;
  27. }
  28. function getAccessorCacheKey(accessor, bufferView) {
  29. const byteOffset = bufferView.byteOffset + accessor.byteOffset;
  30. const { componentType, type, count } = accessor;
  31. return `${byteOffset}-${componentType}-${type}-${count}`;
  32. }
  33. function getEmbeddedBufferCacheKey(parentResource, bufferId) {
  34. const parentCacheKey = getExternalResourceCacheKey(parentResource);
  35. return `${parentCacheKey}-buffer-id-${bufferId}`;
  36. }
  37. function getBufferCacheKey(buffer, bufferId, gltfResource, baseResource) {
  38. if (defined(buffer.uri)) {
  39. const resource = baseResource.getDerivedResource({
  40. url: buffer.uri,
  41. });
  42. return getExternalResourceCacheKey(resource);
  43. }
  44. return getEmbeddedBufferCacheKey(gltfResource, bufferId);
  45. }
  46. function getDracoCacheKey(gltf, draco, gltfResource, baseResource) {
  47. const bufferViewId = draco.bufferView;
  48. const bufferView = gltf.bufferViews[bufferViewId];
  49. const bufferId = bufferView.buffer;
  50. const buffer = gltf.buffers[bufferId];
  51. const bufferCacheKey = getBufferCacheKey(
  52. buffer,
  53. bufferId,
  54. gltfResource,
  55. baseResource,
  56. );
  57. const bufferViewCacheKey = getBufferViewCacheKey(bufferView);
  58. return `${bufferCacheKey}-range-${bufferViewCacheKey}`;
  59. }
  60. function getSpzCacheKey(gltf, primitive, gltfResource, baseResource) {
  61. const bufferViewId = 0;
  62. const bufferView = gltf.bufferViews[bufferViewId];
  63. const bufferId = bufferView.buffer;
  64. const buffer = gltf.buffers[bufferId];
  65. const bufferCacheKey = getBufferCacheKey(
  66. buffer,
  67. bufferId,
  68. gltfResource,
  69. baseResource,
  70. );
  71. const bufferViewCacheKey = getBufferViewCacheKey(bufferView);
  72. return `${bufferCacheKey}-range-${bufferViewCacheKey}`;
  73. }
  74. function getImageCacheKey(gltf, imageId, gltfResource, baseResource) {
  75. const image = gltf.images[imageId];
  76. const bufferViewId = image.bufferView;
  77. const uri = image.uri;
  78. if (defined(uri)) {
  79. const resource = baseResource.getDerivedResource({
  80. url: uri,
  81. });
  82. return getExternalResourceCacheKey(resource);
  83. }
  84. const bufferView = gltf.bufferViews[bufferViewId];
  85. const bufferId = bufferView.buffer;
  86. const buffer = gltf.buffers[bufferId];
  87. const bufferCacheKey = getBufferCacheKey(
  88. buffer,
  89. bufferId,
  90. gltfResource,
  91. baseResource,
  92. );
  93. const bufferViewCacheKey = getBufferViewCacheKey(bufferView);
  94. return `${bufferCacheKey}-range-${bufferViewCacheKey}`;
  95. }
  96. function getSamplerCacheKey(gltf, textureInfo) {
  97. const sampler = GltfLoaderUtil.createSampler({
  98. gltf: gltf,
  99. textureInfo: textureInfo,
  100. });
  101. return `${sampler.wrapS}-${sampler.wrapT}-${sampler.minificationFilter}-${sampler.magnificationFilter}`;
  102. }
  103. /**
  104. * Gets the schema cache key.
  105. *
  106. * @param {object} options Object with the following properties:
  107. * @param {object} [options.schema] An object that explicitly defines a schema JSON. Mutually exclusive with options.resource.
  108. * @param {Resource} [options.resource] The {@link Resource} pointing to the schema JSON. Mutually exclusive with options.schema.
  109. *
  110. * @returns {string} The schema cache key.
  111. *
  112. * @exception {DeveloperError} One of options.schema and options.resource must be defined.
  113. * @private
  114. */
  115. ResourceCacheKey.getSchemaCacheKey = function (options) {
  116. const { schema, resource } = options;
  117. //>>includeStart('debug', pragmas.debug);
  118. if (defined(schema) === defined(resource)) {
  119. throw new DeveloperError(
  120. "One of options.schema and options.resource must be defined.",
  121. );
  122. }
  123. //>>includeEnd('debug');
  124. if (defined(schema)) {
  125. return `embedded-schema:${JSON.stringify(schema)}`;
  126. }
  127. return `external-schema:${getExternalResourceCacheKey(resource)}`;
  128. };
  129. /**
  130. * Gets the external buffer cache key.
  131. *
  132. * @param {object} options Object with the following properties:
  133. * @param {Resource} options.resource The {@link Resource} pointing to the external buffer.
  134. *
  135. * @returns {string} The external buffer cache key.
  136. * @private
  137. */
  138. ResourceCacheKey.getExternalBufferCacheKey = function (options) {
  139. options = options ?? Frozen.EMPTY_OBJECT;
  140. const { resource } = options;
  141. //>>includeStart('debug', pragmas.debug);
  142. Check.typeOf.object("options.resource", resource);
  143. //>>includeEnd('debug');
  144. return `external-buffer:${getExternalResourceCacheKey(resource)}`;
  145. };
  146. /**
  147. * Gets the embedded buffer cache key.
  148. *
  149. * @param {object} options Object with the following properties:
  150. * @param {Resource} options.parentResource The {@link Resource} containing the embedded buffer.
  151. * @param {number} options.bufferId A unique identifier of the embedded buffer within the parent resource.
  152. *
  153. * @returns {string} The embedded buffer cache key.
  154. * @private
  155. */
  156. ResourceCacheKey.getEmbeddedBufferCacheKey = function (options) {
  157. options = options ?? Frozen.EMPTY_OBJECT;
  158. const { parentResource, bufferId } = options;
  159. //>>includeStart('debug', pragmas.debug);
  160. Check.typeOf.object("options.parentResource", parentResource);
  161. Check.typeOf.number("options.bufferId", bufferId);
  162. //>>includeEnd('debug');
  163. return `embedded-buffer:${getEmbeddedBufferCacheKey(
  164. parentResource,
  165. bufferId,
  166. )}`;
  167. };
  168. /**
  169. * Gets the glTF cache key.
  170. *
  171. * @param {object} options Object with the following properties:
  172. * @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
  173. *
  174. * @returns {string} The glTF cache key.
  175. * @private
  176. */
  177. ResourceCacheKey.getGltfCacheKey = function (options) {
  178. options = options ?? Frozen.EMPTY_OBJECT;
  179. const { gltfResource } = options;
  180. //>>includeStart('debug', pragmas.debug);
  181. Check.typeOf.object("options.gltfResource", gltfResource);
  182. //>>includeEnd('debug');
  183. return `gltf:${getExternalResourceCacheKey(gltfResource)}`;
  184. };
  185. /**
  186. * Gets the buffer view cache key.
  187. *
  188. * @param {object} options Object with the following properties:
  189. * @param {object} options.gltf The glTF JSON.
  190. * @param {number} options.bufferViewId The bufferView ID.
  191. * @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
  192. * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
  193. *
  194. * @returns {string} The buffer view cache key.
  195. * @private
  196. */
  197. ResourceCacheKey.getBufferViewCacheKey = function (options) {
  198. options = options ?? Frozen.EMPTY_OBJECT;
  199. const { gltf, bufferViewId, gltfResource, baseResource } = options;
  200. //>>includeStart('debug', pragmas.debug);
  201. Check.typeOf.object("options.gltf", gltf);
  202. Check.typeOf.number("options.bufferViewId", bufferViewId);
  203. Check.typeOf.object("options.gltfResource", gltfResource);
  204. Check.typeOf.object("options.baseResource", baseResource);
  205. //>>includeEnd('debug');
  206. const bufferView = gltf.bufferViews[bufferViewId];
  207. let bufferId = bufferView.buffer;
  208. const buffer = gltf.buffers[bufferId];
  209. if (hasExtension(bufferView, "EXT_meshopt_compression")) {
  210. const meshopt = bufferView.extensions.EXT_meshopt_compression;
  211. bufferId = meshopt.buffer;
  212. }
  213. const bufferCacheKey = getBufferCacheKey(
  214. buffer,
  215. bufferId,
  216. gltfResource,
  217. baseResource,
  218. );
  219. const bufferViewCacheKey = getBufferViewCacheKey(bufferView);
  220. return `buffer-view:${bufferCacheKey}-range-${bufferViewCacheKey}`;
  221. };
  222. /**
  223. * Gets the Draco cache key.
  224. *
  225. * @param {object} options Object with the following properties:
  226. * @param {object} options.gltf The glTF JSON.
  227. * @param {object} options.draco The Draco extension object.
  228. * @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
  229. * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
  230. *
  231. * @returns {string} The Draco cache key.
  232. * @private
  233. */
  234. ResourceCacheKey.getDracoCacheKey = function (options) {
  235. options = options ?? Frozen.EMPTY_OBJECT;
  236. const { gltf, draco, gltfResource, baseResource } = options;
  237. //>>includeStart('debug', pragmas.debug);
  238. Check.typeOf.object("options.gltf", gltf);
  239. Check.typeOf.object("options.draco", draco);
  240. Check.typeOf.object("options.gltfResource", gltfResource);
  241. Check.typeOf.object("options.baseResource", baseResource);
  242. //>>includeEnd('debug');
  243. return `draco:${getDracoCacheKey(gltf, draco, gltfResource, baseResource)}`;
  244. };
  245. ResourceCacheKey.getSpzCacheKey = function (options) {
  246. options = options ?? Frozen.EMPTY_OBJECT;
  247. const { gltf, primitive, gltfResource, baseResource } = options;
  248. //>>includeStart('debug', pragmas.debug);
  249. Check.typeOf.object("options.gltf", gltf);
  250. Check.typeOf.object("options.primitive", primitive);
  251. Check.typeOf.object("options.gltfResource", gltfResource);
  252. Check.typeOf.object("options.baseResource", baseResource);
  253. //>>includeEnd('debug');
  254. return `spz:${getSpzCacheKey(gltf, primitive, gltfResource, baseResource)}`;
  255. };
  256. /**
  257. * Gets the vertex buffer cache key.
  258. *
  259. * @param {object} options Object with the following properties:
  260. * @param {object} options.gltf The glTF JSON.
  261. * @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
  262. * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
  263. * @param {FrameState} options.frameState The frame state.
  264. * @param {number} [options.bufferViewId] The bufferView ID corresponding to the vertex buffer.
  265. * @param {object} [options.draco] The Draco extension object.
  266. * @param {string} [options.attributeSemantic] The attribute semantic, e.g. POSITION or NORMAL.
  267. * @param {boolean} [options.dequantize=false] Determines whether or not the vertex buffer will be dequantized on the CPU.
  268. * @param {boolean} [options.loadBuffer=false] Load vertex buffer as a GPU vertex buffer.
  269. * @param {boolean} [options.loadTypedArray=false] Load vertex buffer as a typed array.
  270. * @exception {DeveloperError} One of options.bufferViewId and options.draco must be defined.
  271. * @exception {DeveloperError} When options.draco is defined options.attributeSemantic must also be defined.
  272. *
  273. * @returns {string} The vertex buffer cache key.
  274. * @private
  275. */
  276. ResourceCacheKey.getVertexBufferCacheKey = function (options) {
  277. options = options ?? Frozen.EMPTY_OBJECT;
  278. const {
  279. gltf,
  280. gltfResource,
  281. baseResource,
  282. frameState,
  283. bufferViewId,
  284. draco,
  285. spz,
  286. attributeSemantic,
  287. dequantize = false,
  288. loadBuffer = false,
  289. loadTypedArray = false,
  290. } = options;
  291. //>>includeStart('debug', pragmas.debug);
  292. Check.typeOf.object("options.gltf", gltf);
  293. Check.typeOf.object("options.gltfResource", gltfResource);
  294. Check.typeOf.object("options.baseResource", baseResource);
  295. Check.typeOf.object("options.frameState", frameState);
  296. const hasBufferViewId = defined(bufferViewId);
  297. const hasDraco = hasDracoCompression(draco, attributeSemantic);
  298. const hasAttributeSemantic = defined(attributeSemantic);
  299. const hasSpz = defined(spz);
  300. if (hasBufferViewId === (hasDraco !== hasSpz)) {
  301. throw new DeveloperError(
  302. "One of options.bufferViewId and options.draco must be defined.",
  303. );
  304. }
  305. if (hasDraco && !hasAttributeSemantic) {
  306. throw new DeveloperError(
  307. "When options.draco is defined options.attributeSemantic must also be defined.",
  308. );
  309. }
  310. if (hasDraco) {
  311. Check.typeOf.object("options.draco", draco);
  312. Check.typeOf.string("options.attributeSemantic", attributeSemantic);
  313. }
  314. if (!loadBuffer && !loadTypedArray) {
  315. throw new DeveloperError(
  316. "At least one of loadBuffer and loadTypedArray must be true.",
  317. );
  318. }
  319. //>>includeEnd('debug');
  320. let cacheKeySuffix = "";
  321. if (dequantize) {
  322. cacheKeySuffix += "-dequantize";
  323. }
  324. if (loadBuffer) {
  325. cacheKeySuffix += "-buffer";
  326. cacheKeySuffix += `-context-${frameState.context.id}`;
  327. }
  328. if (loadTypedArray) {
  329. cacheKeySuffix += "-typed-array";
  330. }
  331. if (defined(draco)) {
  332. const dracoCacheKey = getDracoCacheKey(
  333. gltf,
  334. draco,
  335. gltfResource,
  336. baseResource,
  337. );
  338. return `vertex-buffer:${dracoCacheKey}-draco-${attributeSemantic}${cacheKeySuffix}`;
  339. }
  340. if (spz) {
  341. const spzCacheKey = getSpzCacheKey(gltf, spz, gltfResource, baseResource);
  342. return `vertex-buffer:${spzCacheKey}-spz-${attributeSemantic}${cacheKeySuffix}`;
  343. }
  344. const bufferView = gltf.bufferViews[bufferViewId];
  345. const bufferId = bufferView.buffer;
  346. const buffer = gltf.buffers[bufferId];
  347. const bufferCacheKey = getBufferCacheKey(
  348. buffer,
  349. bufferId,
  350. gltfResource,
  351. baseResource,
  352. );
  353. const bufferViewCacheKey = getBufferViewCacheKey(bufferView);
  354. return `vertex-buffer:${bufferCacheKey}-range-${bufferViewCacheKey}${cacheKeySuffix}`;
  355. };
  356. function hasDracoCompression(draco, semantic) {
  357. return (
  358. defined(draco) &&
  359. defined(draco.attributes) &&
  360. defined(draco.attributes[semantic])
  361. );
  362. }
  363. /**
  364. * Gets the index buffer cache key.
  365. *
  366. * @param {object} options Object with the following properties:
  367. * @param {object} options.gltf The glTF JSON.
  368. * @param {number} options.accessorId The accessor ID corresponding to the index buffer.
  369. * @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
  370. * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
  371. * @param {FrameState} options.frameState The frame state.
  372. * @param {object} [options.draco] The Draco extension object.
  373. * @param {boolean} [options.loadBuffer=false] Load index buffer as a GPU index buffer.
  374. * @param {boolean} [options.loadTypedArray=false] Load index buffer as a typed array.
  375. *
  376. * @returns {string} The index buffer cache key.
  377. * @private
  378. */
  379. ResourceCacheKey.getIndexBufferCacheKey = function (options) {
  380. options = options ?? Frozen.EMPTY_OBJECT;
  381. const {
  382. gltf,
  383. accessorId,
  384. gltfResource,
  385. baseResource,
  386. frameState,
  387. draco,
  388. loadBuffer = false,
  389. loadTypedArray = false,
  390. } = options;
  391. //>>includeStart('debug', pragmas.debug);
  392. Check.typeOf.object("options.gltf", gltf);
  393. Check.typeOf.number("options.accessorId", accessorId);
  394. Check.typeOf.object("options.gltfResource", gltfResource);
  395. Check.typeOf.object("options.baseResource", baseResource);
  396. Check.typeOf.object("options.frameState", frameState);
  397. if (!loadBuffer && !loadTypedArray) {
  398. throw new DeveloperError(
  399. "At least one of loadBuffer and loadTypedArray must be true.",
  400. );
  401. }
  402. //>>includeEnd('debug');
  403. let cacheKeySuffix = "";
  404. if (loadBuffer) {
  405. cacheKeySuffix += "-buffer";
  406. cacheKeySuffix += `-context-${frameState.context.id}`;
  407. }
  408. if (loadTypedArray) {
  409. cacheKeySuffix += "-typed-array";
  410. }
  411. if (defined(draco)) {
  412. const dracoCacheKey = getDracoCacheKey(
  413. gltf,
  414. draco,
  415. gltfResource,
  416. baseResource,
  417. );
  418. return `index-buffer:${dracoCacheKey}-draco${cacheKeySuffix}`;
  419. }
  420. const accessor = gltf.accessors[accessorId];
  421. const bufferViewId = accessor.bufferView;
  422. const bufferView = gltf.bufferViews[bufferViewId];
  423. const bufferId = bufferView.buffer;
  424. const buffer = gltf.buffers[bufferId];
  425. const bufferCacheKey = getBufferCacheKey(
  426. buffer,
  427. bufferId,
  428. gltfResource,
  429. baseResource,
  430. );
  431. const accessorCacheKey = getAccessorCacheKey(accessor, bufferView);
  432. return `index-buffer:${bufferCacheKey}-accessor-${accessorCacheKey}${cacheKeySuffix}`;
  433. };
  434. /**
  435. * Gets the image cache key.
  436. *
  437. * @param {object} options Object with the following properties:
  438. * @param {object} options.gltf The glTF JSON.
  439. * @param {number} options.imageId The image ID.
  440. * @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
  441. * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
  442. *
  443. * @returns {string} The image cache key.
  444. * @private
  445. */
  446. ResourceCacheKey.getImageCacheKey = function (options) {
  447. options = options ?? Frozen.EMPTY_OBJECT;
  448. const { gltf, imageId, gltfResource, baseResource } = options;
  449. //>>includeStart('debug', pragmas.debug);
  450. Check.typeOf.object("options.gltf", gltf);
  451. Check.typeOf.number("options.imageId", imageId);
  452. Check.typeOf.object("options.gltfResource", gltfResource);
  453. Check.typeOf.object("options.baseResource", baseResource);
  454. //>>includeEnd('debug');
  455. const imageCacheKey = getImageCacheKey(
  456. gltf,
  457. imageId,
  458. gltfResource,
  459. baseResource,
  460. );
  461. return `image:${imageCacheKey}`;
  462. };
  463. /**
  464. * Gets the texture cache key.
  465. *
  466. * @param {object} options Object with the following properties:
  467. * @param {object} options.gltf The glTF JSON.
  468. * @param {object} options.textureInfo The texture info object.
  469. * @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
  470. * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
  471. * @param {SupportedImageFormats} options.supportedImageFormats The supported image formats.
  472. * @param {FrameState} options.frameState The frame state.
  473. *
  474. * @returns {string} The texture cache key.
  475. * @private
  476. */
  477. ResourceCacheKey.getTextureCacheKey = function (options) {
  478. options = options ?? Frozen.EMPTY_OBJECT;
  479. const {
  480. gltf,
  481. textureInfo,
  482. gltfResource,
  483. baseResource,
  484. supportedImageFormats,
  485. frameState,
  486. } = options;
  487. //>>includeStart('debug', pragmas.debug);
  488. Check.typeOf.object("options.gltf", gltf);
  489. Check.typeOf.object("options.textureInfo", textureInfo);
  490. Check.typeOf.object("options.gltfResource", gltfResource);
  491. Check.typeOf.object("options.baseResource", baseResource);
  492. Check.typeOf.object("options.supportedImageFormats", supportedImageFormats);
  493. Check.typeOf.object("options.frameState", frameState);
  494. //>>includeEnd('debug');
  495. const textureId = textureInfo.index;
  496. const imageId = GltfLoaderUtil.getImageIdFromTexture({
  497. gltf: gltf,
  498. textureId: textureId,
  499. supportedImageFormats: supportedImageFormats,
  500. });
  501. const imageCacheKey = getImageCacheKey(
  502. gltf,
  503. imageId,
  504. gltfResource,
  505. baseResource,
  506. );
  507. // Include the sampler cache key in the texture cache key since textures and
  508. // samplers are coupled in WebGL 1. When upgrading to WebGL 2 consider
  509. // removing the sampleCacheKey here.
  510. const samplerCacheKey = getSamplerCacheKey(gltf, textureInfo);
  511. return `texture:${imageCacheKey}-sampler-${samplerCacheKey}-context-${frameState.context.id}`;
  512. };
  513. export default ResourceCacheKey;