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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. import Check from "../Core/Check.js";
  2. import Frozen from "../Core/Frozen.js";
  3. import defined from "../Core/defined.js";
  4. import destroyObject from "../Core/destroyObject.js";
  5. import DeveloperError from "../Core/DeveloperError.js";
  6. import PixelFormat from "../Core/PixelFormat.js";
  7. import ContextLimits from "./ContextLimits.js";
  8. import PixelDatatype from "./PixelDatatype.js";
  9. function attachTexture(framebuffer, attachment, texture) {
  10. const gl = framebuffer._gl;
  11. gl.framebufferTexture2D(
  12. gl.FRAMEBUFFER,
  13. attachment,
  14. texture._target,
  15. texture._texture,
  16. 0,
  17. );
  18. }
  19. function attachRenderbuffer(framebuffer, attachment, renderbuffer) {
  20. const gl = framebuffer._gl;
  21. gl.framebufferRenderbuffer(
  22. gl.FRAMEBUFFER,
  23. attachment,
  24. gl.RENDERBUFFER,
  25. renderbuffer._getRenderbuffer(),
  26. );
  27. }
  28. /**
  29. * Creates a framebuffer with optional initial color, depth, and stencil attachments.
  30. * Framebuffers are used for render-to-texture effects; they allow us to render to
  31. * textures in one pass, and read from it in a later pass.
  32. *
  33. * @param {object} options Object with the following properties:
  34. * @param {Context} options.context
  35. * @param {Texture[]} [options.colorTextures]
  36. * @param {Renderbuffer[]} [options.colorRenderbuffers]
  37. * @param {Texture} [options.depthTexture]
  38. * @param {Renderbuffer} [options.depthRenderbuffer]
  39. * @param {Renderbuffer} [options.stencilRenderbuffer]
  40. * @param {Texture} [options.depthStencilTexture]
  41. * @param {Renderbuffer} [options.depthStencilRenderbuffer]
  42. * @param {boolean} [options.destroyAttachments=true] When true, the framebuffer owns its attachments so they will be destroyed when {@link Framebuffer#destroy} is called or when a new attachment is assigned to an attachment point.
  43. *
  44. * @exception {DeveloperError} Cannot have both color texture and color renderbuffer attachments.
  45. * @exception {DeveloperError} Cannot have both a depth texture and depth renderbuffer attachment.
  46. * @exception {DeveloperError} Cannot have both a depth-stencil texture and depth-stencil renderbuffer attachment.
  47. * @exception {DeveloperError} Cannot have both a depth and depth-stencil renderbuffer.
  48. * @exception {DeveloperError} Cannot have both a stencil and depth-stencil renderbuffer.
  49. * @exception {DeveloperError} Cannot have both a depth and stencil renderbuffer.
  50. * @exception {DeveloperError} The color-texture pixel-format must be a color format.
  51. * @exception {DeveloperError} The depth-texture pixel-format must be DEPTH_COMPONENT.
  52. * @exception {DeveloperError} The depth-stencil-texture pixel-format must be DEPTH_STENCIL.
  53. * @exception {DeveloperError} The number of color attachments exceeds the number supported.
  54. * @exception {DeveloperError} The color-texture pixel datatype is HALF_FLOAT and the WebGL implementation does not support the EXT_color_buffer_half_float extension.
  55. * @exception {DeveloperError} The color-texture pixel datatype is FLOAT and the WebGL implementation does not support the EXT_color_buffer_float or WEBGL_color_buffer_float extensions.
  56. *
  57. * @example
  58. * // Create a framebuffer with color and depth texture attachments.
  59. * const width = context.canvas.clientWidth;
  60. * const height = context.canvas.clientHeight;
  61. * const framebuffer = new Framebuffer({
  62. * context : context,
  63. * colorTextures : [new Texture({
  64. * context : context,
  65. * width : width,
  66. * height : height,
  67. * pixelFormat : PixelFormat.RGBA
  68. * })],
  69. * depthTexture : new Texture({
  70. * context : context,
  71. * width : width,
  72. * height : height,
  73. * pixelFormat : PixelFormat.DEPTH_COMPONENT,
  74. * pixelDatatype : PixelDatatype.UNSIGNED_SHORT
  75. * })
  76. * });
  77. *
  78. * @private
  79. * @constructor
  80. */
  81. function Framebuffer(options) {
  82. options = options ?? Frozen.EMPTY_OBJECT;
  83. const context = options.context;
  84. //>>includeStart('debug', pragmas.debug);
  85. Check.defined("options.context", context);
  86. //>>includeEnd('debug');
  87. const gl = context._gl;
  88. const maximumColorAttachments = ContextLimits.maximumColorAttachments;
  89. this._gl = gl;
  90. this._framebuffer = gl.createFramebuffer();
  91. this._colorTextures = [];
  92. this._colorRenderbuffers = [];
  93. this._activeColorAttachments = [];
  94. this._depthTexture = undefined;
  95. this._depthRenderbuffer = undefined;
  96. this._stencilRenderbuffer = undefined;
  97. this._depthStencilTexture = undefined;
  98. this._depthStencilRenderbuffer = undefined;
  99. /**
  100. * When true, the framebuffer owns its attachments so they will be destroyed when
  101. * {@link Framebuffer#destroy} is called or when a new attachment is assigned
  102. * to an attachment point.
  103. *
  104. * @type {boolean}
  105. * @default true
  106. *
  107. * @see Framebuffer#destroy
  108. */
  109. this.destroyAttachments = options.destroyAttachments ?? true;
  110. // Throw if a texture and renderbuffer are attached to the same point. This won't
  111. // cause a WebGL error (because only one will be attached), but is likely a developer error.
  112. //>>includeStart('debug', pragmas.debug);
  113. if (defined(options.colorTextures) && defined(options.colorRenderbuffers)) {
  114. throw new DeveloperError(
  115. "Cannot have both color texture and color renderbuffer attachments.",
  116. );
  117. }
  118. if (defined(options.depthTexture) && defined(options.depthRenderbuffer)) {
  119. throw new DeveloperError(
  120. "Cannot have both a depth texture and depth renderbuffer attachment.",
  121. );
  122. }
  123. if (
  124. defined(options.depthStencilTexture) &&
  125. defined(options.depthStencilRenderbuffer)
  126. ) {
  127. throw new DeveloperError(
  128. "Cannot have both a depth-stencil texture and depth-stencil renderbuffer attachment.",
  129. );
  130. }
  131. // Avoid errors defined in Section 6.5 of the WebGL spec
  132. const depthAttachment =
  133. defined(options.depthTexture) || defined(options.depthRenderbuffer);
  134. const depthStencilAttachment =
  135. defined(options.depthStencilTexture) ||
  136. defined(options.depthStencilRenderbuffer);
  137. if (depthAttachment && depthStencilAttachment) {
  138. throw new DeveloperError(
  139. "Cannot have both a depth and depth-stencil attachment.",
  140. );
  141. }
  142. if (defined(options.stencilRenderbuffer) && depthStencilAttachment) {
  143. throw new DeveloperError(
  144. "Cannot have both a stencil and depth-stencil attachment.",
  145. );
  146. }
  147. if (depthAttachment && defined(options.stencilRenderbuffer)) {
  148. throw new DeveloperError(
  149. "Cannot have both a depth and stencil attachment.",
  150. );
  151. }
  152. //>>includeEnd('debug');
  153. this._bind();
  154. if (defined(options.colorTextures)) {
  155. const textures = options.colorTextures;
  156. const length =
  157. (this._colorTextures.length =
  158. this._activeColorAttachments.length =
  159. textures.length);
  160. //>>includeStart('debug', pragmas.debug);
  161. if (length > maximumColorAttachments) {
  162. throw new DeveloperError(
  163. "The number of color attachments exceeds the number supported.",
  164. );
  165. }
  166. //>>includeEnd('debug');
  167. for (let i = 0; i < length; ++i) {
  168. const texture = textures[i];
  169. //>>includeStart('debug', pragmas.debug);
  170. if (!PixelFormat.isColorFormat(texture.pixelFormat)) {
  171. throw new DeveloperError(
  172. "The color-texture pixel-format must be a color format.",
  173. );
  174. }
  175. if (
  176. texture.pixelDatatype === PixelDatatype.FLOAT &&
  177. !context.colorBufferFloat
  178. ) {
  179. throw new DeveloperError(
  180. "The color texture pixel datatype is FLOAT and the WebGL implementation does not support the EXT_color_buffer_float or WEBGL_color_buffer_float extensions. See Context.colorBufferFloat.",
  181. );
  182. }
  183. if (
  184. texture.pixelDatatype === PixelDatatype.HALF_FLOAT &&
  185. !context.colorBufferHalfFloat
  186. ) {
  187. throw new DeveloperError(
  188. "The color texture pixel datatype is HALF_FLOAT and the WebGL implementation does not support the EXT_color_buffer_half_float extension. See Context.colorBufferHalfFloat.",
  189. );
  190. }
  191. //>>includeEnd('debug');
  192. const attachmentEnum = this._gl.COLOR_ATTACHMENT0 + i;
  193. attachTexture(this, attachmentEnum, texture);
  194. this._activeColorAttachments[i] = attachmentEnum;
  195. this._colorTextures[i] = texture;
  196. }
  197. }
  198. if (defined(options.colorRenderbuffers)) {
  199. const renderbuffers = options.colorRenderbuffers;
  200. const length =
  201. (this._colorRenderbuffers.length =
  202. this._activeColorAttachments.length =
  203. renderbuffers.length);
  204. //>>includeStart('debug', pragmas.debug);
  205. if (length > maximumColorAttachments) {
  206. throw new DeveloperError(
  207. "The number of color attachments exceeds the number supported.",
  208. );
  209. }
  210. //>>includeEnd('debug');
  211. for (let i = 0; i < length; ++i) {
  212. const renderbuffer = renderbuffers[i];
  213. const attachmentEnum = this._gl.COLOR_ATTACHMENT0 + i;
  214. attachRenderbuffer(this, attachmentEnum, renderbuffer);
  215. this._activeColorAttachments[i] = attachmentEnum;
  216. this._colorRenderbuffers[i] = renderbuffer;
  217. }
  218. }
  219. if (defined(options.depthTexture)) {
  220. const texture = options.depthTexture;
  221. //>>includeStart('debug', pragmas.debug);
  222. if (texture.pixelFormat !== PixelFormat.DEPTH_COMPONENT) {
  223. throw new DeveloperError(
  224. "The depth-texture pixel-format must be DEPTH_COMPONENT.",
  225. );
  226. }
  227. //>>includeEnd('debug');
  228. attachTexture(this, this._gl.DEPTH_ATTACHMENT, texture);
  229. this._depthTexture = texture;
  230. }
  231. if (defined(options.depthRenderbuffer)) {
  232. const renderbuffer = options.depthRenderbuffer;
  233. attachRenderbuffer(this, this._gl.DEPTH_ATTACHMENT, renderbuffer);
  234. this._depthRenderbuffer = renderbuffer;
  235. }
  236. if (defined(options.stencilRenderbuffer)) {
  237. const renderbuffer = options.stencilRenderbuffer;
  238. attachRenderbuffer(this, this._gl.STENCIL_ATTACHMENT, renderbuffer);
  239. this._stencilRenderbuffer = renderbuffer;
  240. }
  241. if (defined(options.depthStencilTexture)) {
  242. const texture = options.depthStencilTexture;
  243. //>>includeStart('debug', pragmas.debug);
  244. if (texture.pixelFormat !== PixelFormat.DEPTH_STENCIL) {
  245. throw new DeveloperError(
  246. "The depth-stencil pixel-format must be DEPTH_STENCIL.",
  247. );
  248. }
  249. //>>includeEnd('debug');
  250. attachTexture(this, this._gl.DEPTH_STENCIL_ATTACHMENT, texture);
  251. this._depthStencilTexture = texture;
  252. }
  253. if (defined(options.depthStencilRenderbuffer)) {
  254. const renderbuffer = options.depthStencilRenderbuffer;
  255. attachRenderbuffer(this, this._gl.DEPTH_STENCIL_ATTACHMENT, renderbuffer);
  256. this._depthStencilRenderbuffer = renderbuffer;
  257. }
  258. this._unBind();
  259. }
  260. Object.defineProperties(Framebuffer.prototype, {
  261. /**
  262. * The status of the framebuffer. If the status is not WebGLConstants.FRAMEBUFFER_COMPLETE,
  263. * a {@link DeveloperError} will be thrown when attempting to render to the framebuffer.
  264. * @memberof Framebuffer.prototype
  265. * @type {number}
  266. */
  267. status: {
  268. get: function () {
  269. this._bind();
  270. const status = this._gl.checkFramebufferStatus(this._gl.FRAMEBUFFER);
  271. this._unBind();
  272. return status;
  273. },
  274. },
  275. numberOfColorAttachments: {
  276. get: function () {
  277. return this._activeColorAttachments.length;
  278. },
  279. },
  280. depthTexture: {
  281. get: function () {
  282. return this._depthTexture;
  283. },
  284. },
  285. depthRenderbuffer: {
  286. get: function () {
  287. return this._depthRenderbuffer;
  288. },
  289. },
  290. stencilRenderbuffer: {
  291. get: function () {
  292. return this._stencilRenderbuffer;
  293. },
  294. },
  295. depthStencilTexture: {
  296. get: function () {
  297. return this._depthStencilTexture;
  298. },
  299. },
  300. depthStencilRenderbuffer: {
  301. get: function () {
  302. return this._depthStencilRenderbuffer;
  303. },
  304. },
  305. /**
  306. * True if the framebuffer has a depth attachment. Depth attachments include
  307. * depth and depth-stencil textures, and depth and depth-stencil renderbuffers. When
  308. * rendering to a framebuffer, a depth attachment is required for the depth test to have effect.
  309. * @memberof Framebuffer.prototype
  310. * @type {boolean}
  311. */
  312. hasDepthAttachment: {
  313. get: function () {
  314. return !!(
  315. this.depthTexture ||
  316. this.depthRenderbuffer ||
  317. this.depthStencilTexture ||
  318. this.depthStencilRenderbuffer
  319. );
  320. },
  321. },
  322. });
  323. Framebuffer.prototype._bind = function () {
  324. const gl = this._gl;
  325. gl.bindFramebuffer(gl.FRAMEBUFFER, this._framebuffer);
  326. };
  327. Framebuffer.prototype._unBind = function () {
  328. const gl = this._gl;
  329. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  330. };
  331. Framebuffer.prototype.bindDraw = function () {
  332. const gl = this._gl;
  333. gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this._framebuffer);
  334. };
  335. Framebuffer.prototype.bindRead = function () {
  336. const gl = this._gl;
  337. gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this._framebuffer);
  338. };
  339. Framebuffer.prototype._getActiveColorAttachments = function () {
  340. return this._activeColorAttachments;
  341. };
  342. Framebuffer.prototype.getColorTexture = function (index) {
  343. //>>includeStart('debug', pragmas.debug);
  344. if (!defined(index) || index < 0 || index >= this._colorTextures.length) {
  345. throw new DeveloperError(
  346. "index is required, must be greater than or equal to zero and must be less than the number of color attachments.",
  347. );
  348. }
  349. //>>includeEnd('debug');
  350. return this._colorTextures[index];
  351. };
  352. Framebuffer.prototype.getColorRenderbuffer = function (index) {
  353. //>>includeStart('debug', pragmas.debug);
  354. if (
  355. !defined(index) ||
  356. index < 0 ||
  357. index >= this._colorRenderbuffers.length
  358. ) {
  359. throw new DeveloperError(
  360. "index is required, must be greater than or equal to zero and must be less than the number of color attachments.",
  361. );
  362. }
  363. //>>includeEnd('debug');
  364. return this._colorRenderbuffers[index];
  365. };
  366. Framebuffer.prototype.isDestroyed = function () {
  367. return false;
  368. };
  369. Framebuffer.prototype.destroy = function () {
  370. if (this.destroyAttachments) {
  371. // If the color texture is a cube map face, it is owned by the cube map, and will not be destroyed.
  372. const textures = this._colorTextures;
  373. for (let i = 0; i < textures.length; ++i) {
  374. const texture = textures[i];
  375. if (defined(texture)) {
  376. texture.destroy();
  377. }
  378. }
  379. const renderbuffers = this._colorRenderbuffers;
  380. for (let i = 0; i < renderbuffers.length; ++i) {
  381. const renderbuffer = renderbuffers[i];
  382. if (defined(renderbuffer)) {
  383. renderbuffer.destroy();
  384. }
  385. }
  386. this._depthTexture = this._depthTexture && this._depthTexture.destroy();
  387. this._depthRenderbuffer =
  388. this._depthRenderbuffer && this._depthRenderbuffer.destroy();
  389. this._stencilRenderbuffer =
  390. this._stencilRenderbuffer && this._stencilRenderbuffer.destroy();
  391. this._depthStencilTexture =
  392. this._depthStencilTexture && this._depthStencilTexture.destroy();
  393. this._depthStencilRenderbuffer =
  394. this._depthStencilRenderbuffer &&
  395. this._depthStencilRenderbuffer.destroy();
  396. }
  397. this._gl.deleteFramebuffer(this._framebuffer);
  398. return destroyObject(this);
  399. };
  400. export default Framebuffer;