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

GltfIndexBufferLoader.js 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. import Check from "../Core/Check.js";
  2. import ComponentDatatype from "../Core/ComponentDatatype.js";
  3. import Frozen from "../Core/Frozen.js";
  4. import defined from "../Core/defined.js";
  5. import deprecationWarning from "../Core/deprecationWarning.js";
  6. import DeveloperError from "../Core/DeveloperError.js";
  7. import IndexDatatype from "../Core/IndexDatatype.js";
  8. import Buffer from "../Renderer/Buffer.js";
  9. import BufferUsage from "../Renderer/BufferUsage.js";
  10. import JobType from "./JobType.js";
  11. import ResourceLoader from "./ResourceLoader.js";
  12. import ResourceLoaderState from "./ResourceLoaderState.js";
  13. /**
  14. * Loads an index buffer from a glTF accessor.
  15. * <p>
  16. * Implements the {@link ResourceLoader} interface.
  17. * </p>
  18. *
  19. * @private
  20. */
  21. class GltfIndexBufferLoader extends ResourceLoader {
  22. /**
  23. * @param {object} options Object with the following properties:
  24. * @param {ResourceCache} options.resourceCache The {@link ResourceCache} (to avoid circular dependencies).
  25. * @param {object} options.gltf The glTF JSON.
  26. * @param {number} options.accessorId The accessor ID corresponding to the index buffer.
  27. * @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
  28. * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
  29. * @param {object} [options.primitive] The primitive containing the Draco extension.
  30. * @param {object} [options.draco] The Draco extension object.
  31. * @param {string} [options.cacheKey] The cache key of the resource.
  32. * @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.
  33. * @param {boolean} [options.loadBuffer=false] Load the index buffer as a GPU index buffer.
  34. * @param {boolean} [options.loadTypedArray=false] Load the index buffer as a typed array.
  35. */
  36. constructor(options) {
  37. super();
  38. options = options ?? Frozen.EMPTY_OBJECT;
  39. const resourceCache = options.resourceCache;
  40. const gltf = options.gltf;
  41. const accessorId = options.accessorId;
  42. const gltfResource = options.gltfResource;
  43. const baseResource = options.baseResource;
  44. const primitive = options.primitive;
  45. const draco = options.draco;
  46. const cacheKey = options.cacheKey;
  47. const asynchronous = options.asynchronous ?? true;
  48. const loadBuffer = options.loadBuffer ?? false;
  49. const loadTypedArray = options.loadTypedArray ?? false;
  50. //>>includeStart('debug', pragmas.debug);
  51. Check.typeOf.func("options.resourceCache", resourceCache);
  52. Check.typeOf.object("options.gltf", gltf);
  53. Check.typeOf.number("options.accessorId", accessorId);
  54. Check.typeOf.object("options.gltfResource", gltfResource);
  55. Check.typeOf.object("options.baseResource", baseResource);
  56. if (!loadBuffer && !loadTypedArray) {
  57. throw new DeveloperError(
  58. "At least one of loadBuffer and loadTypedArray must be true.",
  59. );
  60. }
  61. //>>includeEnd('debug');
  62. const indexDatatype = gltf.accessors[accessorId].componentType;
  63. this._resourceCache = resourceCache;
  64. this._gltfResource = gltfResource;
  65. this._baseResource = baseResource;
  66. this._gltf = gltf;
  67. this._accessorId = accessorId;
  68. this._indexDatatype = indexDatatype;
  69. this._primitive = primitive;
  70. this._draco = draco;
  71. this._cacheKey = cacheKey;
  72. this._asynchronous = asynchronous;
  73. this._loadBuffer = loadBuffer;
  74. this._loadTypedArray = loadTypedArray;
  75. this._bufferViewLoader = undefined;
  76. this._dracoLoader = undefined;
  77. this._typedArray = undefined;
  78. this._buffer = undefined;
  79. this._state = ResourceLoaderState.UNLOADED;
  80. this._promise = undefined;
  81. }
  82. /**
  83. * The cache key of the resource.
  84. *
  85. *
  86. * @type {string}
  87. * @readonly
  88. * @private
  89. */
  90. get cacheKey() {
  91. return this._cacheKey;
  92. }
  93. /**
  94. * The index buffer. This is only defined when <code>loadBuffer</code> is true.
  95. *
  96. *
  97. * @type {Buffer}
  98. * @readonly
  99. * @private
  100. */
  101. get buffer() {
  102. return this._buffer;
  103. }
  104. /**
  105. * The typed array containing indices. This is only defined when <code>loadTypedArray</code> is true.
  106. *
  107. *
  108. * @type {Uint8Array|Uint16Array|Uint32Array}
  109. * @readonly
  110. * @private
  111. */
  112. get typedArray() {
  113. return this._typedArray;
  114. }
  115. /**
  116. * The index datatype after decode.
  117. *
  118. *
  119. * @type {IndexDatatype}
  120. * @readonly
  121. * @private
  122. */
  123. get indexDatatype() {
  124. return this._indexDatatype;
  125. }
  126. /**
  127. * Loads the resource.
  128. * @returns {Promise<GltfIndexBufferLoader>} A promise which resolves to the loader when the resource loading is completed.
  129. * @private
  130. */
  131. async load() {
  132. if (defined(this._promise)) {
  133. return this._promise;
  134. }
  135. if (defined(this._draco)) {
  136. this._promise = loadFromDraco(this);
  137. return this._promise;
  138. }
  139. this._promise = loadFromBufferView(this);
  140. return this._promise;
  141. }
  142. /**
  143. * Processes the resource until it becomes ready.
  144. *
  145. * @param {FrameState} frameState The frame state.
  146. * @private
  147. */
  148. process(frameState) {
  149. //>>includeStart('debug', pragmas.debug);
  150. Check.typeOf.object("frameState", frameState);
  151. //>>includeEnd('debug');
  152. if (this._state === ResourceLoaderState.READY) {
  153. return true;
  154. }
  155. if (
  156. this._state !== ResourceLoaderState.LOADED &&
  157. this._state !== ResourceLoaderState.PROCESSING
  158. ) {
  159. return false;
  160. }
  161. let typedArray = this._typedArray;
  162. let indexDatatype = this._indexDatatype;
  163. if (defined(this._dracoLoader)) {
  164. try {
  165. const ready = this._dracoLoader.process(frameState);
  166. if (ready) {
  167. const dracoLoader = this._dracoLoader;
  168. typedArray = dracoLoader.decodedData.indices.typedArray;
  169. this._typedArray = typedArray;
  170. // The index datatype may be a smaller datatype after draco decode
  171. indexDatatype = ComponentDatatype.fromTypedArray(typedArray);
  172. this._indexDatatype = indexDatatype;
  173. }
  174. } catch (error) {
  175. handleError(this, error);
  176. }
  177. }
  178. if (!defined(typedArray)) {
  179. // Buffer view hasn't been loaded yet
  180. return false;
  181. }
  182. let buffer;
  183. if (this._loadBuffer && this._asynchronous) {
  184. const indexBufferJob = scratchIndexBufferJob;
  185. indexBufferJob.set(typedArray, indexDatatype, frameState.context);
  186. const jobScheduler = frameState.jobScheduler;
  187. if (!jobScheduler.execute(indexBufferJob, JobType.BUFFER)) {
  188. // Job scheduler is full. Try again next frame.
  189. return false;
  190. }
  191. buffer = indexBufferJob.buffer;
  192. } else if (this._loadBuffer) {
  193. buffer = createIndexBuffer(typedArray, indexDatatype, frameState.context);
  194. }
  195. // Unload everything except the index buffer and/or typed array.
  196. this.unload();
  197. this._buffer = buffer;
  198. this._typedArray = this._loadTypedArray ? typedArray : undefined;
  199. this._state = ResourceLoaderState.READY;
  200. this._resourceCache.statistics.addGeometryLoader(this);
  201. return true;
  202. }
  203. /**
  204. * Unloads the resource.
  205. * @private
  206. */
  207. unload() {
  208. if (defined(this._buffer)) {
  209. this._buffer.destroy();
  210. }
  211. const resourceCache = this._resourceCache;
  212. if (
  213. defined(this._bufferViewLoader) &&
  214. !this._bufferViewLoader.isDestroyed()
  215. ) {
  216. resourceCache.unload(this._bufferViewLoader);
  217. }
  218. if (defined(this._dracoLoader)) {
  219. resourceCache.unload(this._dracoLoader);
  220. }
  221. this._bufferViewLoader = undefined;
  222. this._dracoLoader = undefined;
  223. this._typedArray = undefined;
  224. this._buffer = undefined;
  225. this._gltf = undefined;
  226. this._primitive = undefined;
  227. }
  228. }
  229. class CreateIndexBufferJob {
  230. constructor() {
  231. this.typedArray = undefined;
  232. this.indexDatatype = undefined;
  233. this.context = undefined;
  234. this.buffer = undefined;
  235. }
  236. set(typedArray, indexDatatype, context) {
  237. this.typedArray = typedArray;
  238. this.indexDatatype = indexDatatype;
  239. this.context = context;
  240. }
  241. execute() {
  242. this.buffer = createIndexBuffer(
  243. this.typedArray,
  244. this.indexDatatype,
  245. this.context,
  246. );
  247. }
  248. }
  249. function createIndexBuffer(typedArray, indexDatatype, context) {
  250. const buffer = Buffer.createIndexBuffer({
  251. typedArray: typedArray,
  252. context: context,
  253. usage: BufferUsage.STATIC_DRAW,
  254. indexDatatype: indexDatatype,
  255. });
  256. buffer.vertexArrayDestroyable = false;
  257. return buffer;
  258. }
  259. const scratchIndexBufferJob = new CreateIndexBufferJob();
  260. async function loadFromDraco(indexBufferLoader) {
  261. indexBufferLoader._state = ResourceLoaderState.LOADING;
  262. const resourceCache = indexBufferLoader._resourceCache;
  263. try {
  264. const dracoLoader = resourceCache.getDracoLoader({
  265. gltf: indexBufferLoader._gltf,
  266. primitive: indexBufferLoader._primitive,
  267. draco: indexBufferLoader._draco,
  268. gltfResource: indexBufferLoader._gltfResource,
  269. baseResource: indexBufferLoader._baseResource,
  270. });
  271. indexBufferLoader._dracoLoader = dracoLoader;
  272. await dracoLoader.load();
  273. if (indexBufferLoader.isDestroyed()) {
  274. return;
  275. }
  276. // Now wait for process() to run to finish loading
  277. indexBufferLoader._state = ResourceLoaderState.LOADED;
  278. return indexBufferLoader;
  279. } catch (error) {
  280. if (indexBufferLoader.isDestroyed()) {
  281. return;
  282. }
  283. handleError(indexBufferLoader, error);
  284. }
  285. }
  286. async function loadFromBufferView(indexBufferLoader) {
  287. const gltf = indexBufferLoader._gltf;
  288. const accessorId = indexBufferLoader._accessorId;
  289. const accessor = gltf.accessors[accessorId];
  290. const bufferViewId = accessor.bufferView;
  291. indexBufferLoader._state = ResourceLoaderState.LOADING;
  292. const resourceCache = indexBufferLoader._resourceCache;
  293. try {
  294. const bufferViewLoader = resourceCache.getBufferViewLoader({
  295. gltf: gltf,
  296. bufferViewId: bufferViewId,
  297. gltfResource: indexBufferLoader._gltfResource,
  298. baseResource: indexBufferLoader._baseResource,
  299. });
  300. indexBufferLoader._bufferViewLoader = bufferViewLoader;
  301. await bufferViewLoader.load();
  302. if (indexBufferLoader.isDestroyed()) {
  303. return;
  304. }
  305. const bufferViewTypedArray = bufferViewLoader.typedArray;
  306. indexBufferLoader._typedArray = createIndicesTypedArray(
  307. indexBufferLoader,
  308. bufferViewTypedArray,
  309. );
  310. indexBufferLoader._state = ResourceLoaderState.PROCESSING;
  311. return indexBufferLoader;
  312. } catch (error) {
  313. if (indexBufferLoader.isDestroyed()) {
  314. return;
  315. }
  316. handleError(indexBufferLoader, error);
  317. }
  318. }
  319. function createIndicesTypedArray(indexBufferLoader, bufferViewTypedArray) {
  320. const gltf = indexBufferLoader._gltf;
  321. const accessorId = indexBufferLoader._accessorId;
  322. const accessor = gltf.accessors[accessorId];
  323. const count = accessor.count;
  324. const indexDatatype = accessor.componentType;
  325. const indexSize = IndexDatatype.getSizeInBytes(indexDatatype);
  326. let arrayBuffer = bufferViewTypedArray.buffer;
  327. let byteOffset = bufferViewTypedArray.byteOffset + accessor.byteOffset;
  328. if (byteOffset % indexSize !== 0) {
  329. const byteLength = count * indexSize;
  330. const view = new Uint8Array(arrayBuffer, byteOffset, byteLength);
  331. const copy = new Uint8Array(view);
  332. arrayBuffer = copy.buffer;
  333. byteOffset = 0;
  334. deprecationWarning(
  335. "index-buffer-unaligned",
  336. `The index array is not aligned to a ${indexSize}-byte boundary.`,
  337. );
  338. }
  339. let typedArray;
  340. if (indexDatatype === IndexDatatype.UNSIGNED_BYTE) {
  341. typedArray = new Uint8Array(arrayBuffer, byteOffset, count);
  342. } else if (indexDatatype === IndexDatatype.UNSIGNED_SHORT) {
  343. typedArray = new Uint16Array(arrayBuffer, byteOffset, count);
  344. } else if (indexDatatype === IndexDatatype.UNSIGNED_INT) {
  345. typedArray = new Uint32Array(arrayBuffer, byteOffset, count);
  346. }
  347. return typedArray;
  348. }
  349. function handleError(indexBufferLoader, error) {
  350. indexBufferLoader.unload();
  351. indexBufferLoader._state = ResourceLoaderState.FAILED;
  352. const errorMessage = "Failed to load index buffer";
  353. throw indexBufferLoader.getError(errorMessage, error);
  354. }
  355. export default GltfIndexBufferLoader;