Home Reference Source

cables_dev/cables/src/core/cgl/cgl_framebuffer.js

  1. import { Logger } from "cables-shared-client";
  2. import { Texture } from "./cgl_texture.js";
  3.  
  4. // todo: convert to prototyped...
  5.  
  6. /**
  7. * a framebuffer
  8. * @constructor
  9. * @class
  10. * @constructs Framebuffer
  11. * @param {Context} _cgl cgl
  12. * @param {Number} _w width
  13. * @param {Number} _h height
  14. * @param {Object} options
  15. */
  16. const Framebuffer = function (_cgl, _w, _h, options)
  17. {
  18. const cgl = _cgl;
  19. this._log = new Logger("Framebuffer");
  20. this.valid = true;
  21.  
  22. let depthTextureExt = cgl.gl.DEPTH_TEXTURE;
  23. if (!depthTextureExt) depthTextureExt = cgl.enableExtension("WEBGL_depth_texture");
  24. if (!depthTextureExt) depthTextureExt = cgl.enableExtension("WEBKIT_WEBGL_depth_texture");
  25. if (!depthTextureExt) depthTextureExt = cgl.enableExtension("MOZ_WEBGL_depth_texture");
  26.  
  27. if (!depthTextureExt)
  28. {
  29. this._log.error("NO_DEPTH_TEXTURE", "no depth texture support");
  30. return;
  31. }
  32.  
  33. let width = _w || 512;
  34. let height = _h || 512;
  35.  
  36. options = options || {
  37. "isFloatingPointTexture": false,
  38. };
  39.  
  40. if (!options.hasOwnProperty("clear")) options.clear = true;
  41. if (!options.hasOwnProperty("filter")) options.filter = Texture.FILTER_LINEAR;
  42.  
  43. const texture = new Texture(cgl, {
  44. "isFloatingPointTexture": options.isFloatingPointTexture,
  45. "filter": options.filter,
  46. "wrap": options.wrap || Texture.CLAMP_TO_EDGE
  47. });
  48.  
  49. let textureDepth = null;
  50. if (depthTextureExt)
  51. {
  52. textureDepth = new Texture(cgl, {
  53. "isDepthTexture": true,
  54. });
  55. }
  56. this._options = options;
  57.  
  58. const frameBuf = cgl.gl.createFramebuffer();
  59. const depthBuffer = cgl.gl.createRenderbuffer();
  60.  
  61. this.getWidth = function ()
  62. {
  63. return width;
  64. };
  65. this.getHeight = function ()
  66. {
  67. return height;
  68. };
  69.  
  70. /**
  71. * get native gl framebuffer
  72. * @function getGlFrameBuffer
  73. * @memberof Framebuffer
  74. * @returns {Object} framebuffer
  75. */
  76. this.getGlFrameBuffer = function ()
  77. {
  78. return frameBuf;
  79. };
  80.  
  81. /**
  82. * get depth renderbuffer
  83. * @function getDepthRenderBuffer
  84. * @memberof Framebuffer
  85. * @returns {Object} renderbuffer
  86. */
  87. this.getDepthRenderBuffer = function ()
  88. {
  89. return depthBuffer;
  90. };
  91.  
  92. /**
  93. * get color texture
  94. * @function getTextureColor
  95. * @memberof Framebuffer
  96. * @returns {Texture} rgba texture
  97. */
  98. this.getTextureColor = function ()
  99. {
  100. return texture;
  101. };
  102.  
  103. /**
  104. * get depth texture
  105. * @function getTextureDepth
  106. * @memberof Framebuffer
  107. * @returns {Texture} depth texture
  108. */
  109. this.getTextureDepth = function ()
  110. {
  111. return textureDepth;
  112. };
  113.  
  114. this.setFilter = function (f)
  115. {
  116. texture.filter = f;
  117. texture.setSize(width, height);
  118. };
  119.  
  120. this.setSize = function (w, h)
  121. {
  122. if (w < 2) w = 2;
  123. if (h < 2) h = 2;
  124.  
  125. width = Math.ceil(w);
  126. height = Math.ceil(h);
  127.  
  128. cgl.profileData.profileFrameBuffercreate++;
  129.  
  130. cgl.gl.bindFramebuffer(cgl.gl.FRAMEBUFFER, frameBuf);
  131. cgl.gl.bindRenderbuffer(cgl.gl.RENDERBUFFER, depthBuffer);
  132.  
  133. texture.setSize(width, height);
  134. if (textureDepth) textureDepth.setSize(width, height);
  135.  
  136. // if(depthTextureExt) cgl.gl.renderbufferStorage(cgl.gl.RENDERBUFFER, cgl.gl.DEPTH_COMPONENT16, width,height);
  137. if (depthTextureExt) cgl.gl.renderbufferStorage(cgl.gl.RENDERBUFFER, cgl.gl.DEPTH_COMPONENT16, width, height);
  138.  
  139. cgl.gl.framebufferTexture2D(cgl.gl.FRAMEBUFFER, cgl.gl.COLOR_ATTACHMENT0, cgl.gl.TEXTURE_2D, texture.tex, 0);
  140.  
  141. if (depthTextureExt)
  142. {
  143. cgl.gl.framebufferRenderbuffer(cgl.gl.FRAMEBUFFER, cgl.gl.DEPTH_ATTACHMENT, cgl.gl.RENDERBUFFER, depthBuffer);
  144. cgl.gl.framebufferTexture2D(
  145. cgl.gl.FRAMEBUFFER,
  146. cgl.gl.DEPTH_ATTACHMENT, // safari needs DEPTH_ATTACHMENT NOT DEPTH_ATTACHMENT16
  147. // cgl.gl.DEPTH_COMPONENT16,
  148. cgl.gl.TEXTURE_2D,
  149. textureDepth.tex,
  150. 0,
  151. );
  152. }
  153.  
  154. if (!cgl.gl.isFramebuffer(frameBuf)) throw new Error("Invalid framebuffer");
  155. const status = cgl.gl.checkFramebufferStatus(cgl.gl.FRAMEBUFFER);
  156.  
  157. switch (status)
  158. {
  159. case cgl.gl.FRAMEBUFFER_COMPLETE:
  160. break;
  161. case cgl.gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
  162. this._log.warn("FRAMEBUFFER_INCOMPLETE_ATTACHMENT...", width, height, texture.tex, depthBuffer);
  163. this.valid = false;
  164. throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
  165. case cgl.gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
  166. this._log.warn("FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
  167. this.valid = false;
  168. throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
  169. case cgl.gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
  170. this._log.warn("FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
  171. this.valid = false;
  172. throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
  173. case cgl.gl.FRAMEBUFFER_UNSUPPORTED:
  174. this._log.warn("FRAMEBUFFER_UNSUPPORTED");
  175. this.valid = false;
  176. this._log.warn(width, height, options);
  177.  
  178. throw new Error("Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED");
  179. case 0x8CDB:
  180. this._log.warn("Incomplete: FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER from ext. Or Safari/iOS undefined behaviour.");
  181. this.valid = false;
  182. break;
  183. default:
  184. this._log.warn("incomplete framebuffer", status);
  185. this.valid = false;
  186. throw new Error("Incomplete framebuffer: " + status);
  187. }
  188.  
  189. cgl.gl.bindTexture(cgl.gl.TEXTURE_2D, null);
  190. cgl.gl.bindRenderbuffer(cgl.gl.RENDERBUFFER, null);
  191. cgl.gl.bindFramebuffer(cgl.gl.FRAMEBUFFER, null);
  192. };
  193.  
  194. this.renderStart = function ()
  195. {
  196. cgl.pushModelMatrix();
  197. cgl.gl.bindFramebuffer(cgl.gl.FRAMEBUFFER, frameBuf);
  198. cgl.pushGlFrameBuffer(frameBuf);
  199. cgl.pushFrameBuffer(this);
  200.  
  201. cgl.pushPMatrix();
  202. cgl.gl.viewport(0, 0, width, height);
  203.  
  204. if (this._options.clear)
  205. {
  206. cgl.gl.clearColor(0, 0, 0, 0);
  207. cgl.gl.clear(cgl.gl.COLOR_BUFFER_BIT | cgl.gl.DEPTH_BUFFER_BIT);
  208. }
  209. };
  210.  
  211. this.renderEnd = function ()
  212. {
  213. cgl.popPMatrix();
  214. cgl.gl.bindFramebuffer(cgl.gl.FRAMEBUFFER, cgl.popGlFrameBuffer());
  215. cgl.popFrameBuffer();
  216.  
  217. cgl.popModelMatrix();
  218. cgl.resetViewPort();
  219. };
  220.  
  221.  
  222. this.delete = function ()
  223. {
  224. texture.delete();
  225. this.valid = false;
  226. if (textureDepth) textureDepth.delete();
  227. cgl.gl.deleteRenderbuffer(depthBuffer);
  228. cgl.gl.deleteFramebuffer(frameBuf);
  229. };
  230.  
  231. this.dispose = this.delete;
  232.  
  233. this.setSize(width, height);
  234. };
  235.  
  236. export { Framebuffer };