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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. import Check from "../Core/Check.js";
  2. import createGuid from "../Core/createGuid.js";
  3. import Frozen from "../Core/Frozen.js";
  4. import defined from "../Core/defined.js";
  5. import destroyObject from "../Core/destroyObject.js";
  6. import DeveloperError from "../Core/DeveloperError.js";
  7. import IndexDatatype from "../Core/IndexDatatype.js";
  8. import WebGLConstants from "../Core/WebGLConstants.js";
  9. import BufferUsage from "./BufferUsage.js";
  10. /**
  11. * @private
  12. */
  13. function Buffer(options) {
  14. options = options ?? Frozen.EMPTY_OBJECT;
  15. //>>includeStart('debug', pragmas.debug);
  16. Check.defined("options.context", options.context);
  17. if (!defined(options.typedArray) && !defined(options.sizeInBytes)) {
  18. throw new DeveloperError(
  19. "Either options.sizeInBytes or options.typedArray is required.",
  20. );
  21. }
  22. if (defined(options.typedArray) && defined(options.sizeInBytes)) {
  23. throw new DeveloperError(
  24. "Cannot pass in both options.sizeInBytes and options.typedArray.",
  25. );
  26. }
  27. if (defined(options.typedArray)) {
  28. Check.typeOf.object("options.typedArray", options.typedArray);
  29. Check.typeOf.number(
  30. "options.typedArray.byteLength",
  31. options.typedArray.byteLength,
  32. );
  33. }
  34. if (!BufferUsage.validate(options.usage)) {
  35. throw new DeveloperError("usage is invalid.");
  36. }
  37. //>>includeEnd('debug');
  38. const gl = options.context._gl;
  39. const bufferTarget = options.bufferTarget;
  40. const typedArray = options.typedArray;
  41. let sizeInBytes = options.sizeInBytes;
  42. const usage = options.usage;
  43. const hasArray = defined(typedArray);
  44. if (hasArray) {
  45. sizeInBytes = typedArray.byteLength;
  46. }
  47. //>>includeStart('debug', pragmas.debug);
  48. Check.typeOf.number.greaterThan("sizeInBytes", sizeInBytes, 0);
  49. //>>includeEnd('debug');
  50. const buffer = gl.createBuffer();
  51. gl.bindBuffer(bufferTarget, buffer);
  52. gl.bufferData(bufferTarget, hasArray ? typedArray : sizeInBytes, usage);
  53. gl.bindBuffer(bufferTarget, null);
  54. this._id = createGuid();
  55. this._gl = gl;
  56. this._webgl2 = options.context._webgl2;
  57. this._bufferTarget = bufferTarget;
  58. this._sizeInBytes = sizeInBytes;
  59. this._usage = usage;
  60. this._buffer = buffer;
  61. this.vertexArrayDestroyable = true;
  62. }
  63. Buffer.createPixelBuffer = function (options) {
  64. //>>includeStart('debug', pragmas.debug);
  65. Check.defined("options.context", options.context);
  66. //>>includeEnd('debug');
  67. if (!options.context._webgl2) {
  68. throw new DeveloperError(
  69. "A WebGL 2 context is required to create PixelBuffers.",
  70. );
  71. }
  72. return new Buffer({
  73. context: options.context,
  74. bufferTarget: WebGLConstants.PIXEL_PACK_BUFFER,
  75. typedArray: options.typedArray,
  76. sizeInBytes: options.sizeInBytes,
  77. usage: options.usage,
  78. });
  79. };
  80. /**
  81. * Creates a vertex buffer, which contains untyped vertex data in GPU-controlled memory.
  82. * <br /><br />
  83. * A vertex array defines the actual makeup of a vertex, e.g., positions, normals, texture coordinates,
  84. * etc., by interpreting the raw data in one or more vertex buffers.
  85. *
  86. * @param {object} options An object containing the following properties:
  87. * @param {Context} options.context The context in which to create the buffer
  88. * @param {ArrayBufferView} [options.typedArray] A typed array containing the data to copy to the buffer.
  89. * @param {number} [options.sizeInBytes] A <code>Number</code> defining the size of the buffer in bytes. Required if options.typedArray is not given.
  90. * @param {BufferUsage} options.usage Specifies the expected usage pattern of the buffer. On some GL implementations, this can significantly affect performance. See {@link BufferUsage}.
  91. * @returns {VertexBuffer} The vertex buffer, ready to be attached to a vertex array.
  92. *
  93. * @exception {DeveloperError} Must specify either <options.typedArray> or <options.sizeInBytes>, but not both.
  94. * @exception {DeveloperError} The buffer size must be greater than zero.
  95. * @exception {DeveloperError} Invalid <code>usage</code>.
  96. *
  97. *
  98. * @example
  99. * // Example 1. Create a dynamic vertex buffer 16 bytes in size.
  100. * const buffer = Buffer.createVertexBuffer({
  101. * context : context,
  102. * sizeInBytes : 16,
  103. * usage : BufferUsage.DYNAMIC_DRAW
  104. * });
  105. *
  106. * @example
  107. * // Example 2. Create a dynamic vertex buffer from three floating-point values.
  108. * // The data copied to the vertex buffer is considered raw bytes until it is
  109. * // interpreted as vertices using a vertex array.
  110. * const positionBuffer = buffer.createVertexBuffer({
  111. * context : context,
  112. * typedArray : new Float32Array([0, 0, 0]),
  113. * usage : BufferUsage.STATIC_DRAW
  114. * });
  115. *
  116. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGenBuffer.xml|glGenBuffer}
  117. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBindBuffer.xml|glBindBuffer} with <code>ARRAY_BUFFER</code>
  118. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBufferData.xml|glBufferData} with <code>ARRAY_BUFFER</code>
  119. */
  120. Buffer.createVertexBuffer = function (options) {
  121. //>>includeStart('debug', pragmas.debug);
  122. Check.defined("options.context", options.context);
  123. //>>includeEnd('debug');
  124. return new Buffer({
  125. context: options.context,
  126. bufferTarget: WebGLConstants.ARRAY_BUFFER,
  127. typedArray: options.typedArray,
  128. sizeInBytes: options.sizeInBytes,
  129. usage: options.usage,
  130. });
  131. };
  132. /**
  133. * Creates an index buffer, which contains typed indices in GPU-controlled memory.
  134. * <br /><br />
  135. * An index buffer can be attached to a vertex array to select vertices for rendering.
  136. * <code>Context.draw</code> can render using the entire index buffer or a subset
  137. * of the index buffer defined by an offset and count.
  138. *
  139. * @param {object} options An object containing the following properties:
  140. * @param {Context} options.context The context in which to create the buffer
  141. * @param {ArrayBufferView} [options.typedArray] A typed array containing the data to copy to the buffer.
  142. * @param {number} [options.sizeInBytes] A <code>Number</code> defining the size of the buffer in bytes. Required if options.typedArray is not given.
  143. * @param {BufferUsage} options.usage Specifies the expected usage pattern of the buffer. On some GL implementations, this can significantly affect performance. See {@link BufferUsage}.
  144. * @param {IndexDatatype} options.indexDatatype The datatype of indices in the buffer.
  145. * @returns {IndexBuffer} The index buffer, ready to be attached to a vertex array.
  146. *
  147. * @exception {DeveloperError} Must specify either <options.typedArray> or <options.sizeInBytes>, but not both.
  148. * @exception {DeveloperError} IndexDatatype.UNSIGNED_INT requires OES_element_index_uint, which is not supported on this system. Check context.elementIndexUint.
  149. * @exception {DeveloperError} The size in bytes must be greater than zero.
  150. * @exception {DeveloperError} Invalid <code>usage</code>.
  151. * @exception {DeveloperError} Invalid <code>indexDatatype</code>.
  152. *
  153. *
  154. * @example
  155. * // Example 1. Create a stream index buffer of unsigned shorts that is
  156. * // 16 bytes in size.
  157. * const buffer = Buffer.createIndexBuffer({
  158. * context : context,
  159. * sizeInBytes : 16,
  160. * usage : BufferUsage.STREAM_DRAW,
  161. * indexDatatype : IndexDatatype.UNSIGNED_SHORT
  162. * });
  163. *
  164. * @example
  165. * // Example 2. Create a static index buffer containing three unsigned shorts.
  166. * const buffer = Buffer.createIndexBuffer({
  167. * context : context,
  168. * typedArray : new Uint16Array([0, 1, 2]),
  169. * usage : BufferUsage.STATIC_DRAW,
  170. * indexDatatype : IndexDatatype.UNSIGNED_SHORT
  171. * });
  172. *
  173. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGenBuffer.xml|glGenBuffer}
  174. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBindBuffer.xml|glBindBuffer} with <code>ELEMENT_ARRAY_BUFFER</code>
  175. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBufferData.xml|glBufferData} with <code>ELEMENT_ARRAY_BUFFER</code>
  176. */
  177. Buffer.createIndexBuffer = function (options) {
  178. //>>includeStart('debug', pragmas.debug);
  179. Check.defined("options.context", options.context);
  180. if (!IndexDatatype.validate(options.indexDatatype)) {
  181. throw new DeveloperError("Invalid indexDatatype.");
  182. }
  183. if (
  184. options.indexDatatype === IndexDatatype.UNSIGNED_INT &&
  185. !options.context.elementIndexUint
  186. ) {
  187. throw new DeveloperError(
  188. "IndexDatatype.UNSIGNED_INT requires OES_element_index_uint, which is not supported on this system. Check context.elementIndexUint.",
  189. );
  190. }
  191. //>>includeEnd('debug');
  192. const context = options.context;
  193. const indexDatatype = options.indexDatatype;
  194. const bytesPerIndex = IndexDatatype.getSizeInBytes(indexDatatype);
  195. const buffer = new Buffer({
  196. context: context,
  197. bufferTarget: WebGLConstants.ELEMENT_ARRAY_BUFFER,
  198. typedArray: options.typedArray,
  199. sizeInBytes: options.sizeInBytes,
  200. usage: options.usage,
  201. });
  202. const numberOfIndices = buffer.sizeInBytes / bytesPerIndex;
  203. Object.defineProperties(buffer, {
  204. indexDatatype: {
  205. get: function () {
  206. return indexDatatype;
  207. },
  208. },
  209. bytesPerIndex: {
  210. get: function () {
  211. return bytesPerIndex;
  212. },
  213. },
  214. numberOfIndices: {
  215. get: function () {
  216. return numberOfIndices;
  217. },
  218. },
  219. });
  220. return buffer;
  221. };
  222. Object.defineProperties(Buffer.prototype, {
  223. sizeInBytes: {
  224. get: function () {
  225. return this._sizeInBytes;
  226. },
  227. },
  228. usage: {
  229. get: function () {
  230. return this._usage;
  231. },
  232. },
  233. });
  234. Buffer.prototype._getBuffer = function () {
  235. return this._buffer;
  236. };
  237. Buffer.prototype._bind = function () {
  238. const gl = this._gl;
  239. const target = this._bufferTarget;
  240. gl.bindBuffer(target, this._buffer);
  241. };
  242. Buffer.prototype._unBind = function () {
  243. const gl = this._gl;
  244. const target = this._bufferTarget;
  245. gl.bindBuffer(target, null);
  246. };
  247. Buffer.prototype.copyFromArrayView = function (arrayView, offsetInBytes) {
  248. offsetInBytes = offsetInBytes ?? 0;
  249. //>>includeStart('debug', pragmas.debug);
  250. Check.defined("arrayView", arrayView);
  251. Check.typeOf.number.lessThanOrEquals(
  252. "offsetInBytes + arrayView.byteLength",
  253. offsetInBytes + arrayView.byteLength,
  254. this._sizeInBytes,
  255. );
  256. //>>includeEnd('debug');
  257. const gl = this._gl;
  258. const target = this._bufferTarget;
  259. gl.bindBuffer(target, this._buffer);
  260. gl.bufferSubData(target, offsetInBytes, arrayView);
  261. gl.bindBuffer(target, null);
  262. };
  263. Buffer.prototype.copyFromBuffer = function (
  264. readBuffer,
  265. readOffset,
  266. writeOffset,
  267. sizeInBytes,
  268. ) {
  269. //>>includeStart('debug', pragmas.debug);
  270. if (!this._webgl2) {
  271. throw new DeveloperError("A WebGL 2 context is required.");
  272. }
  273. if (!defined(readBuffer)) {
  274. throw new DeveloperError("readBuffer must be defined.");
  275. }
  276. if (!defined(sizeInBytes) || sizeInBytes <= 0) {
  277. throw new DeveloperError(
  278. "sizeInBytes must be defined and be greater than zero.",
  279. );
  280. }
  281. if (
  282. !defined(readOffset) ||
  283. readOffset < 0 ||
  284. readOffset + sizeInBytes > readBuffer._sizeInBytes
  285. ) {
  286. throw new DeveloperError(
  287. "readOffset must be greater than or equal to zero and readOffset + sizeInBytes must be less than of equal to readBuffer.sizeInBytes.",
  288. );
  289. }
  290. if (
  291. !defined(writeOffset) ||
  292. writeOffset < 0 ||
  293. writeOffset + sizeInBytes > this._sizeInBytes
  294. ) {
  295. throw new DeveloperError(
  296. "writeOffset must be greater than or equal to zero and writeOffset + sizeInBytes must be less than of equal to this.sizeInBytes.",
  297. );
  298. }
  299. if (
  300. this._buffer === readBuffer._buffer &&
  301. ((writeOffset >= readOffset && writeOffset < readOffset + sizeInBytes) ||
  302. (readOffset > writeOffset && readOffset < writeOffset + sizeInBytes))
  303. ) {
  304. throw new DeveloperError(
  305. "When readBuffer is equal to this, the ranges [readOffset + sizeInBytes) and [writeOffset, writeOffset + sizeInBytes) must not overlap.",
  306. );
  307. }
  308. if (
  309. (this._bufferTarget === WebGLConstants.ELEMENT_ARRAY_BUFFER &&
  310. readBuffer._bufferTarget !== WebGLConstants.ELEMENT_ARRAY_BUFFER) ||
  311. (this._bufferTarget !== WebGLConstants.ELEMENT_ARRAY_BUFFER &&
  312. readBuffer._bufferTarget === WebGLConstants.ELEMENT_ARRAY_BUFFER)
  313. ) {
  314. throw new DeveloperError(
  315. "Can not copy an index buffer into another buffer type.",
  316. );
  317. }
  318. //>>includeEnd('debug');
  319. const readTarget = WebGLConstants.COPY_READ_BUFFER;
  320. const writeTarget = WebGLConstants.COPY_WRITE_BUFFER;
  321. const gl = this._gl;
  322. gl.bindBuffer(writeTarget, this._buffer);
  323. gl.bindBuffer(readTarget, readBuffer._buffer);
  324. gl.copyBufferSubData(
  325. readTarget,
  326. writeTarget,
  327. readOffset,
  328. writeOffset,
  329. sizeInBytes,
  330. );
  331. gl.bindBuffer(writeTarget, null);
  332. gl.bindBuffer(readTarget, null);
  333. };
  334. Buffer.prototype.getBufferData = function (
  335. arrayView,
  336. sourceOffset,
  337. destinationOffset,
  338. length,
  339. ) {
  340. sourceOffset = sourceOffset ?? 0;
  341. destinationOffset = destinationOffset ?? 0;
  342. //>>includeStart('debug', pragmas.debug);
  343. if (!this._webgl2) {
  344. throw new DeveloperError("A WebGL 2 context is required.");
  345. }
  346. if (!defined(arrayView)) {
  347. throw new DeveloperError("arrayView is required.");
  348. }
  349. let copyLength;
  350. let elementSize;
  351. let arrayLength = arrayView.byteLength;
  352. if (!defined(length)) {
  353. if (defined(arrayLength)) {
  354. copyLength = arrayLength - destinationOffset;
  355. elementSize = 1;
  356. } else {
  357. arrayLength = arrayView.length;
  358. copyLength = arrayLength - destinationOffset;
  359. elementSize = arrayView.BYTES_PER_ELEMENT;
  360. }
  361. } else {
  362. copyLength = length;
  363. if (defined(arrayLength)) {
  364. elementSize = 1;
  365. } else {
  366. arrayLength = arrayView.length;
  367. elementSize = arrayView.BYTES_PER_ELEMENT;
  368. }
  369. }
  370. if (destinationOffset < 0 || destinationOffset > arrayLength) {
  371. throw new DeveloperError(
  372. "destinationOffset must be greater than zero and less than the arrayView length.",
  373. );
  374. }
  375. if (destinationOffset + copyLength > arrayLength) {
  376. throw new DeveloperError(
  377. "destinationOffset + length must be less than or equal to the arrayViewLength.",
  378. );
  379. }
  380. if (sourceOffset < 0 || sourceOffset > this._sizeInBytes) {
  381. throw new DeveloperError(
  382. "sourceOffset must be greater than zero and less than the buffers size.",
  383. );
  384. }
  385. if (sourceOffset + copyLength * elementSize > this._sizeInBytes) {
  386. throw new DeveloperError(
  387. "sourceOffset + length must be less than the buffers size.",
  388. );
  389. }
  390. //>>includeEnd('debug');
  391. const gl = this._gl;
  392. const target = WebGLConstants.COPY_READ_BUFFER;
  393. gl.bindBuffer(target, this._buffer);
  394. gl.getBufferSubData(
  395. target,
  396. sourceOffset,
  397. arrayView,
  398. destinationOffset,
  399. length,
  400. );
  401. gl.bindBuffer(target, null);
  402. };
  403. Buffer.prototype.isDestroyed = function () {
  404. return false;
  405. };
  406. Buffer.prototype.destroy = function () {
  407. this._gl.deleteBuffer(this._buffer);
  408. return destroyObject(this);
  409. };
  410. export default Buffer;