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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. import Check from "../Core/Check.js";
  2. import ComponentDatatype from "../Core/ComponentDatatype.js";
  3. import defined from "../Core/defined.js";
  4. import destroyObject from "../Core/destroyObject.js";
  5. import DeveloperError from "../Core/DeveloperError.js";
  6. import CesiumMath from "../Core/Math.js";
  7. import Buffer from "./Buffer.js";
  8. import BufferUsage from "./BufferUsage.js";
  9. import VertexArray from "./VertexArray.js";
  10. /**
  11. * @private
  12. */
  13. function VertexArrayFacade(context, attributes, sizeInVertices, instanced) {
  14. //>>includeStart('debug', pragmas.debug);
  15. Check.defined("context", context);
  16. if (!attributes || attributes.length === 0) {
  17. throw new DeveloperError("At least one attribute is required.");
  18. }
  19. //>>includeEnd('debug');
  20. const attrs = VertexArrayFacade._verifyAttributes(attributes);
  21. sizeInVertices = sizeInVertices ?? 0;
  22. const precreatedAttributes = [];
  23. const attributesByUsage = {};
  24. let attributesForUsage;
  25. let usage;
  26. // Bucket the attributes by usage.
  27. const length = attrs.length;
  28. for (let i = 0; i < length; ++i) {
  29. const attribute = attrs[i];
  30. // If the attribute already has a vertex buffer, we do not need
  31. // to manage a vertex buffer or typed array for it.
  32. if (attribute.vertexBuffer) {
  33. precreatedAttributes.push(attribute);
  34. continue;
  35. }
  36. usage = attribute.usage;
  37. attributesForUsage = attributesByUsage[usage];
  38. if (!defined(attributesForUsage)) {
  39. attributesForUsage = attributesByUsage[usage] = [];
  40. }
  41. attributesForUsage.push(attribute);
  42. }
  43. // A function to sort attributes by the size of their components. From left to right, a vertex
  44. // stores floats, shorts, and then bytes.
  45. function compare(left, right) {
  46. return (
  47. ComponentDatatype.getSizeInBytes(right.componentDatatype) -
  48. ComponentDatatype.getSizeInBytes(left.componentDatatype)
  49. );
  50. }
  51. this._allBuffers = [];
  52. for (usage in attributesByUsage) {
  53. if (attributesByUsage.hasOwnProperty(usage)) {
  54. attributesForUsage = attributesByUsage[usage];
  55. attributesForUsage.sort(compare);
  56. const vertexSizeInBytes =
  57. VertexArrayFacade._vertexSizeInBytes(attributesForUsage);
  58. const bufferUsage = attributesForUsage[0].usage;
  59. const buffer = {
  60. vertexSizeInBytes: vertexSizeInBytes,
  61. vertexBuffer: undefined,
  62. usage: bufferUsage,
  63. needsCommit: false,
  64. arrayBuffer: undefined,
  65. arrayViews: VertexArrayFacade._createArrayViews(
  66. attributesForUsage,
  67. vertexSizeInBytes,
  68. ),
  69. };
  70. this._allBuffers.push(buffer);
  71. }
  72. }
  73. this._size = 0;
  74. this._instanced = instanced ?? false;
  75. this._precreated = precreatedAttributes;
  76. this._context = context;
  77. this.writers = undefined;
  78. this.va = undefined;
  79. this.resize(sizeInVertices);
  80. }
  81. VertexArrayFacade._verifyAttributes = function (attributes) {
  82. const attrs = [];
  83. for (let i = 0; i < attributes.length; ++i) {
  84. const attribute = attributes[i];
  85. const attr = {
  86. index: attribute.index ?? i,
  87. enabled: attribute.enabled ?? true,
  88. componentsPerAttribute: attribute.componentsPerAttribute,
  89. componentDatatype: attribute.componentDatatype ?? ComponentDatatype.FLOAT,
  90. normalize: attribute.normalize ?? false,
  91. // There will be either a vertexBuffer or an [optional] usage.
  92. vertexBuffer: attribute.vertexBuffer,
  93. usage: attribute.usage ?? BufferUsage.STATIC_DRAW,
  94. };
  95. attrs.push(attr);
  96. //>>includeStart('debug', pragmas.debug);
  97. if (
  98. attr.componentsPerAttribute !== 1 &&
  99. attr.componentsPerAttribute !== 2 &&
  100. attr.componentsPerAttribute !== 3 &&
  101. attr.componentsPerAttribute !== 4
  102. ) {
  103. throw new DeveloperError(
  104. "attribute.componentsPerAttribute must be in the range [1, 4].",
  105. );
  106. }
  107. const datatype = attr.componentDatatype;
  108. if (!ComponentDatatype.validate(datatype)) {
  109. throw new DeveloperError(
  110. "Attribute must have a valid componentDatatype or not specify it.",
  111. );
  112. }
  113. if (!BufferUsage.validate(attr.usage)) {
  114. throw new DeveloperError(
  115. "Attribute must have a valid usage or not specify it.",
  116. );
  117. }
  118. //>>includeEnd('debug');
  119. }
  120. // Verify all attribute names are unique.
  121. const uniqueIndices = new Array(attrs.length);
  122. for (let j = 0; j < attrs.length; ++j) {
  123. const currentAttr = attrs[j];
  124. const index = currentAttr.index;
  125. //>>includeStart('debug', pragmas.debug);
  126. if (uniqueIndices[index]) {
  127. throw new DeveloperError(
  128. `Index ${index} is used by more than one attribute.`,
  129. );
  130. }
  131. //>>includeEnd('debug');
  132. uniqueIndices[index] = true;
  133. }
  134. return attrs;
  135. };
  136. VertexArrayFacade._vertexSizeInBytes = function (attributes) {
  137. let sizeInBytes = 0;
  138. const length = attributes.length;
  139. for (let i = 0; i < length; ++i) {
  140. const attribute = attributes[i];
  141. sizeInBytes +=
  142. attribute.componentsPerAttribute *
  143. ComponentDatatype.getSizeInBytes(attribute.componentDatatype);
  144. }
  145. const maxComponentSizeInBytes =
  146. length > 0
  147. ? ComponentDatatype.getSizeInBytes(attributes[0].componentDatatype)
  148. : 0; // Sorted by size
  149. const remainder =
  150. maxComponentSizeInBytes > 0 ? sizeInBytes % maxComponentSizeInBytes : 0;
  151. const padding = remainder === 0 ? 0 : maxComponentSizeInBytes - remainder;
  152. sizeInBytes += padding;
  153. return sizeInBytes;
  154. };
  155. VertexArrayFacade._createArrayViews = function (attributes, vertexSizeInBytes) {
  156. const views = [];
  157. let offsetInBytes = 0;
  158. const length = attributes.length;
  159. for (let i = 0; i < length; ++i) {
  160. const attribute = attributes[i];
  161. const componentDatatype = attribute.componentDatatype;
  162. views.push({
  163. index: attribute.index,
  164. enabled: attribute.enabled,
  165. componentsPerAttribute: attribute.componentsPerAttribute,
  166. componentDatatype: componentDatatype,
  167. normalize: attribute.normalize,
  168. offsetInBytes: offsetInBytes,
  169. vertexSizeInComponentType:
  170. vertexSizeInBytes / ComponentDatatype.getSizeInBytes(componentDatatype),
  171. view: undefined,
  172. });
  173. offsetInBytes +=
  174. attribute.componentsPerAttribute *
  175. ComponentDatatype.getSizeInBytes(componentDatatype);
  176. }
  177. return views;
  178. };
  179. /**
  180. * Invalidates writers. Can't render again until commit is called.
  181. */
  182. VertexArrayFacade.prototype.resize = function (sizeInVertices) {
  183. this._size = sizeInVertices;
  184. const allBuffers = this._allBuffers;
  185. this.writers = [];
  186. for (let i = 0, len = allBuffers.length; i < len; ++i) {
  187. const buffer = allBuffers[i];
  188. VertexArrayFacade._resize(buffer, this._size);
  189. // Reserving invalidates the writers, so if client's cache them, they need to invalidate their cache.
  190. VertexArrayFacade._appendWriters(this.writers, buffer);
  191. }
  192. // VAs are recreated next time commit is called.
  193. destroyVA(this);
  194. };
  195. VertexArrayFacade._resize = function (buffer, size) {
  196. if (buffer.vertexSizeInBytes > 0) {
  197. // Create larger array buffer
  198. const arrayBuffer = new ArrayBuffer(size * buffer.vertexSizeInBytes);
  199. // Copy contents from previous array buffer
  200. if (defined(buffer.arrayBuffer)) {
  201. const destView = new Uint8Array(arrayBuffer);
  202. const sourceView = new Uint8Array(buffer.arrayBuffer);
  203. const sourceLength = sourceView.length;
  204. for (let j = 0; j < sourceLength; ++j) {
  205. destView[j] = sourceView[j];
  206. }
  207. }
  208. // Create typed views into the new array buffer
  209. const views = buffer.arrayViews;
  210. const length = views.length;
  211. for (let i = 0; i < length; ++i) {
  212. const view = views[i];
  213. view.view = ComponentDatatype.createArrayBufferView(
  214. view.componentDatatype,
  215. arrayBuffer,
  216. view.offsetInBytes,
  217. );
  218. }
  219. buffer.arrayBuffer = arrayBuffer;
  220. }
  221. };
  222. const createWriters = [
  223. // 1 component per attribute
  224. function (buffer, view, vertexSizeInComponentType) {
  225. return function (index, attribute) {
  226. view[index * vertexSizeInComponentType] = attribute;
  227. buffer.needsCommit = true;
  228. };
  229. },
  230. // 2 component per attribute
  231. function (buffer, view, vertexSizeInComponentType) {
  232. return function (index, component0, component1) {
  233. const i = index * vertexSizeInComponentType;
  234. view[i] = component0;
  235. view[i + 1] = component1;
  236. buffer.needsCommit = true;
  237. };
  238. },
  239. // 3 component per attribute
  240. function (buffer, view, vertexSizeInComponentType) {
  241. return function (index, component0, component1, component2) {
  242. const i = index * vertexSizeInComponentType;
  243. view[i] = component0;
  244. view[i + 1] = component1;
  245. view[i + 2] = component2;
  246. buffer.needsCommit = true;
  247. };
  248. },
  249. // 4 component per attribute
  250. function (buffer, view, vertexSizeInComponentType) {
  251. return function (index, component0, component1, component2, component3) {
  252. const i = index * vertexSizeInComponentType;
  253. view[i] = component0;
  254. view[i + 1] = component1;
  255. view[i + 2] = component2;
  256. view[i + 3] = component3;
  257. buffer.needsCommit = true;
  258. };
  259. },
  260. ];
  261. VertexArrayFacade._appendWriters = function (writers, buffer) {
  262. const arrayViews = buffer.arrayViews;
  263. const length = arrayViews.length;
  264. for (let i = 0; i < length; ++i) {
  265. const arrayView = arrayViews[i];
  266. writers[arrayView.index] = createWriters[
  267. arrayView.componentsPerAttribute - 1
  268. ](buffer, arrayView.view, arrayView.vertexSizeInComponentType);
  269. }
  270. };
  271. VertexArrayFacade.prototype.commit = function (indexBuffer) {
  272. let recreateVA = false;
  273. const allBuffers = this._allBuffers;
  274. let buffer;
  275. let i;
  276. let length;
  277. for (i = 0, length = allBuffers.length; i < length; ++i) {
  278. buffer = allBuffers[i];
  279. recreateVA = commit(this, buffer) || recreateVA;
  280. }
  281. ///////////////////////////////////////////////////////////////////////
  282. if (recreateVA || !defined(this.va)) {
  283. destroyVA(this);
  284. const va = (this.va = []);
  285. const chunkSize = CesiumMath.SIXTY_FOUR_KILOBYTES - 4; // The 65535 index is reserved for primitive restart. Reserve the last 4 indices so that billboard quads are not broken up.
  286. const numberOfVertexArrays =
  287. defined(indexBuffer) && !this._instanced
  288. ? Math.ceil(this._size / chunkSize)
  289. : 1;
  290. for (let k = 0; k < numberOfVertexArrays; ++k) {
  291. let attributes = [];
  292. for (i = 0, length = allBuffers.length; i < length; ++i) {
  293. buffer = allBuffers[i];
  294. const offset = k * (buffer.vertexSizeInBytes * chunkSize);
  295. VertexArrayFacade._appendAttributes(
  296. attributes,
  297. buffer,
  298. offset,
  299. this._instanced,
  300. );
  301. }
  302. attributes = attributes.concat(this._precreated);
  303. va.push({
  304. va: new VertexArray({
  305. context: this._context,
  306. attributes: attributes,
  307. indexBuffer: indexBuffer,
  308. }),
  309. indicesCount:
  310. 1.5 *
  311. (k !== numberOfVertexArrays - 1 ? chunkSize : this._size % chunkSize),
  312. // TODO: not hardcode 1.5, this assumes 6 indices per 4 vertices (as for Billboard quads).
  313. });
  314. }
  315. }
  316. };
  317. function commit(vertexArrayFacade, buffer) {
  318. if (buffer.needsCommit && buffer.vertexSizeInBytes > 0) {
  319. buffer.needsCommit = false;
  320. const vertexBuffer = buffer.vertexBuffer;
  321. const vertexBufferSizeInBytes =
  322. vertexArrayFacade._size * buffer.vertexSizeInBytes;
  323. const vertexBufferDefined = defined(vertexBuffer);
  324. if (
  325. !vertexBufferDefined ||
  326. vertexBuffer.sizeInBytes < vertexBufferSizeInBytes
  327. ) {
  328. if (vertexBufferDefined) {
  329. vertexBuffer.destroy();
  330. }
  331. buffer.vertexBuffer = Buffer.createVertexBuffer({
  332. context: vertexArrayFacade._context,
  333. typedArray: buffer.arrayBuffer,
  334. usage: buffer.usage,
  335. });
  336. buffer.vertexBuffer.vertexArrayDestroyable = false;
  337. return true; // Created new vertex buffer
  338. }
  339. buffer.vertexBuffer.copyFromArrayView(buffer.arrayBuffer);
  340. }
  341. return false; // Did not create new vertex buffer
  342. }
  343. VertexArrayFacade._appendAttributes = function (
  344. attributes,
  345. buffer,
  346. vertexBufferOffset,
  347. instanced,
  348. ) {
  349. const arrayViews = buffer.arrayViews;
  350. const length = arrayViews.length;
  351. for (let i = 0; i < length; ++i) {
  352. const view = arrayViews[i];
  353. attributes.push({
  354. index: view.index,
  355. enabled: view.enabled,
  356. componentsPerAttribute: view.componentsPerAttribute,
  357. componentDatatype: view.componentDatatype,
  358. normalize: view.normalize,
  359. vertexBuffer: buffer.vertexBuffer,
  360. offsetInBytes: vertexBufferOffset + view.offsetInBytes,
  361. strideInBytes: buffer.vertexSizeInBytes,
  362. instanceDivisor: instanced ? 1 : 0,
  363. });
  364. }
  365. };
  366. VertexArrayFacade.prototype.subCommit = function (
  367. offsetInVertices,
  368. lengthInVertices,
  369. ) {
  370. //>>includeStart('debug', pragmas.debug);
  371. if (offsetInVertices < 0 || offsetInVertices >= this._size) {
  372. throw new DeveloperError(
  373. "offsetInVertices must be greater than or equal to zero and less than the vertex array size.",
  374. );
  375. }
  376. if (offsetInVertices + lengthInVertices > this._size) {
  377. throw new DeveloperError(
  378. "offsetInVertices + lengthInVertices cannot exceed the vertex array size.",
  379. );
  380. }
  381. //>>includeEnd('debug');
  382. const allBuffers = this._allBuffers;
  383. for (let i = 0, len = allBuffers.length; i < len; ++i) {
  384. subCommit(allBuffers[i], offsetInVertices, lengthInVertices);
  385. }
  386. };
  387. function subCommit(buffer, offsetInVertices, lengthInVertices) {
  388. if (buffer.needsCommit && buffer.vertexSizeInBytes > 0) {
  389. const byteOffset = buffer.vertexSizeInBytes * offsetInVertices;
  390. const byteLength = buffer.vertexSizeInBytes * lengthInVertices;
  391. // PERFORMANCE_IDEA: If we want to get really crazy, we could consider updating
  392. // individual attributes instead of the entire (sub-)vertex.
  393. //
  394. // PERFORMANCE_IDEA: Does creating the typed view add too much GC overhead?
  395. buffer.vertexBuffer.copyFromArrayView(
  396. new Uint8Array(buffer.arrayBuffer, byteOffset, byteLength),
  397. byteOffset,
  398. );
  399. }
  400. }
  401. VertexArrayFacade.prototype.endSubCommits = function () {
  402. const allBuffers = this._allBuffers;
  403. for (let i = 0, len = allBuffers.length; i < len; ++i) {
  404. allBuffers[i].needsCommit = false;
  405. }
  406. };
  407. function destroyVA(vertexArrayFacade) {
  408. const va = vertexArrayFacade.va;
  409. if (!defined(va)) {
  410. return;
  411. }
  412. const length = va.length;
  413. for (let i = 0; i < length; ++i) {
  414. va[i].va.destroy();
  415. }
  416. vertexArrayFacade.va = undefined;
  417. }
  418. VertexArrayFacade.prototype.isDestroyed = function () {
  419. return false;
  420. };
  421. VertexArrayFacade.prototype.destroy = function () {
  422. const allBuffers = this._allBuffers;
  423. for (let i = 0, len = allBuffers.length; i < len; ++i) {
  424. const buffer = allBuffers[i];
  425. buffer.vertexBuffer = buffer.vertexBuffer && buffer.vertexBuffer.destroy();
  426. }
  427. destroyVA(this);
  428. return destroyObject(this);
  429. };
  430. export default VertexArrayFacade;