Home Reference Source

cables_dev/cables/src/libs/cgl/cubemapframebuffer/cubemapframebuffer.js

  1. import { CubemapTexture } from "./cubemaptexture.js";
  2.  
  3. class CubemapFramebuffer
  4. {
  5. constructor(cgl, width, height, options)
  6. {
  7. this._cgl = cgl;
  8. this.width = width || 8;
  9. this.height = height || 8;
  10. this._cubemapProperties = [
  11. // targets for use in some gl functions for working with cubemaps
  12. {
  13. "face": this._cgl.gl.TEXTURE_CUBE_MAP_POSITIVE_X,
  14. "lookAt": vec3.fromValues(1.0, 0.0, 0.0),
  15. "up": vec3.fromValues(0.0, -1.0, 0.0),
  16. },
  17. {
  18. "face": this._cgl.gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
  19. "lookAt": vec3.fromValues(-1.0, 0.0, 0.0),
  20. "up": vec3.fromValues(0.0, -1.0, 0.0),
  21. },
  22. {
  23. "face": this._cgl.gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
  24. "lookAt": vec3.fromValues(0.0, 1.0, 0.0),
  25. "up": vec3.fromValues(0.0, 0.0, 1.0),
  26. },
  27. {
  28. "face": this._cgl.gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
  29. "lookAt": vec3.fromValues(0.0, -1.0, 0.0),
  30. "up": vec3.fromValues(0.0, 0.0, -1.0),
  31. },
  32. {
  33. "face": this._cgl.gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
  34. "lookAt": vec3.fromValues(0.0, 0.0, 1.0),
  35. "up": vec3.fromValues(0.0, -1.0, 0.0),
  36. },
  37. {
  38. "face": this._cgl.gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,
  39. "lookAt": vec3.fromValues(0.0, 0.0, -1.0),
  40. "up": vec3.fromValues(0.0, -1.0, 0.0),
  41. },
  42. ];
  43.  
  44. this._lookAtTemp = vec3.fromValues(0, 0, 0);
  45. this.camPos = vec3.fromValues(0, 0, 0);
  46.  
  47. this._modelMatrix = mat4.create();
  48. this._viewMatrix = mat4.create();
  49. this._projectionMatrix = mat4.perspective(mat4.create(), CGL.DEG2RAD * 90, 1, 0.1, 1000.0);
  50. this._depthRenderbuffer = null;
  51. this._framebuffer = null;
  52. this._depthbuffer = null;
  53. // this._textureFrameBuffer = null;
  54. this._textureDepth = null;
  55.  
  56. this._options = options || {
  57. // "isFloatingPointTexture": false
  58. };
  59.  
  60. this.name = this._options.name || "unknown cubemapframebuffer";
  61. if (!this._options.hasOwnProperty("numRenderBuffers")) this._options.numRenderBuffers = 1;
  62. if (!this._options.hasOwnProperty("depth")) this._options.depth = true;
  63. if (!this._options.hasOwnProperty("clear")) this._options.clear = true;
  64. if (!this._options.hasOwnProperty("multisampling"))
  65. {
  66. this._options.multisampling = false;
  67. this._options.multisamplingSamples = 0;
  68. }
  69.  
  70. if (this._options.multisamplingSamples)
  71. {
  72. if (this._cgl.glSlowRenderer) this._options.multisamplingSamples = 0;
  73. if (!this._cgl.gl.MAX_SAMPLES) this._options.multisamplingSamples = 0;
  74. else this._options.multisamplingSamples = Math.min(this._cgl.gl.getParameter(this._cgl.gl.MAX_SAMPLES), this._options.multisamplingSamples);
  75. }
  76.  
  77. if (!this._options.hasOwnProperty("filter")) this._options.filter = CGL.Texture.FILTER_LINEAR;
  78. if (!this._options.hasOwnProperty("wrap")) this._options.wrap = CGL.Texture.WRAP_CLAMP_TO_EDGE;
  79.  
  80. this._cgl.checkFrameStarted("cubemap framebuffer");
  81.  
  82. let pxlFormat = options.pixeFormat;
  83. if (!pxlFormat && options.isFloatingPointTexture)pxlFormat = CGL.Texture.PFORMATSTR_RGBA32F;
  84.  
  85. this.texture = new CubemapTexture(this._cgl, {
  86. "width": this.width,
  87. "height": this.height,
  88. "pixelFormat": options.pixelFormat,
  89. "filter": this._options.filter,
  90. "wrap": this._options.wrap,
  91. "name": this.name + " cubemaptexture"
  92. });
  93.  
  94. this.initializeRenderbuffers();
  95. this.setSize(this.width, this.height);
  96. }
  97.  
  98. initializeRenderbuffers()
  99. {
  100. this._framebuffer = this._cgl.gl.createFramebuffer(); // crate the framebuffer that will draw to the reflection map
  101. this._depthbuffer = this._cgl.gl.createRenderbuffer(); // renderbuffer for depth buffer in framebuffer
  102.  
  103. this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._framebuffer); // select the framebuffer, so we can attach the depth buffer to it
  104. this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, this._depthbuffer); // so we can create storage for the depthBuffer
  105.  
  106. this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER, this._cgl.gl.DEPTH_COMPONENT16, this.width, this.height);
  107. this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.RENDERBUFFER, this._depthbuffer);
  108.  
  109. this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, null);
  110. this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null);
  111. }
  112.  
  113. getWidth()
  114. {
  115. return this.width;
  116. }
  117.  
  118. getHeight()
  119. {
  120. return this.height;
  121. }
  122.  
  123. getGlFrameBuffer()
  124. {
  125. return this._framebuffer;
  126. }
  127.  
  128. getDepthRenderBuffer()
  129. {
  130. return this._depthRenderbuffer;
  131. }
  132.  
  133. getTextureColor()
  134. {
  135. return this.texture;
  136. }
  137.  
  138. getTextureDepth()
  139. {
  140. return this._textureDepth;
  141. }
  142.  
  143. dispose()
  144. {
  145. if (this.texture) this.texture = this.texture.delete();
  146. if (this._framebuffer) this._cgl.gl.deleteFramebuffer(this._framebuffer);
  147. if (this._depthRenderbuffer) this._cgl.gl.deleteRenderbuffer(this._depthbuffer);
  148. // // if (this._textureFrameBuffer) this._cgl.gl.deleteFramebuffer(this._textureFrameBuffer);
  149. }
  150.  
  151. delete()
  152. {
  153. this.dispose();
  154. }
  155.  
  156. setSize(width, height)
  157. {
  158. // console.log("cubemapframebuffer setsize");
  159. this._cgl.printError("before cubemap setsize");
  160.  
  161. this.width = Math.floor(width);
  162. this.height = Math.floor(height);
  163. this.width = Math.min(this.width, this._cgl.maxTexSize);
  164. this.height = Math.min(this.height, this._cgl.maxTexSize);
  165.  
  166. this._cgl.profileData.profileFrameBuffercreate++;
  167.  
  168. // if (this._framebuffer) this._cgl.gl.deleteFramebuffer(this._framebuffer);
  169. // if (this._depthRenderbuffer) this._cgl.gl.deleteRenderbuffer(this._depthbuffer);
  170. // // if (this._textureFrameBuffer) this._cgl.gl.deleteFramebuffer(this._textureFrameBuffer);
  171.  
  172. this._framebuffer = this._cgl.gl.createFramebuffer();
  173. this._depthbuffer = this._cgl.gl.createRenderbuffer();
  174. this.texture.setSize(this.width, this.height);
  175.  
  176. // this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_CUBE_MAP, this.texture.tex);
  177. this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._framebuffer); // select the framebuffer, so we can attach the depth buffer to it
  178. this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, this._depthbuffer); // so we can create storage for the depthBuffer
  179.  
  180. this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER, this._cgl.gl.DEPTH_COMPONENT16, this.width, this.height);
  181. this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.RENDERBUFFER, this._depthbuffer);
  182.  
  183.  
  184. if (!this._cgl.gl.isFramebuffer(this._framebuffer))
  185. {
  186. console.error("invalid framebuffer...");
  187. // throw new Error("Invalid framebuffer");
  188. }
  189.  
  190.  
  191. // * NOTE: if we check for the error in Safari, we get error code 36059 aka 0x8CDB
  192. // * NOTE: an error that is found in a WebGL extension (WEBGL_draw_buffers) not supported by most iOS devices
  193. // * NOTE: see https://gist.github.com/TimvanScherpenzeel/2a604e178013a5ac4b411fbcbfd2fa33
  194. // * NOTE: also, this error is nowhere to be found in the official WebGL 1 spec
  195. // if (this._cgl.glVersion !== 1)
  196. // {
  197. const status = this._cgl.gl.checkFramebufferStatus(this._cgl.gl.FRAMEBUFFER);
  198. this.checkErrorsByStatus(status);
  199. // }
  200.  
  201. this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_CUBE_MAP, null);
  202. this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, null);
  203. this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null);
  204.  
  205. this._cgl.printError("cubemap setsize");
  206. }
  207.  
  208. checkErrorsByStatus(status)
  209. {
  210. switch (status)
  211. {
  212. case this._cgl.gl.FRAMEBUFFER_COMPLETE:
  213. break;
  214. case this._cgl.gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
  215. console.error("FRAMEBUFFER_INCOMPLETE_ATTACHMENT...", this.width, this.height, this.texture.tex, this._depthBuffer);
  216. throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
  217. case this._cgl.gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
  218. console.error("FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
  219. throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
  220. case this._cgl.gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
  221. console.error("FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
  222. throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
  223. case this._cgl.gl.FRAMEBUFFER_UNSUPPORTED:
  224. console.error("FRAMEBUFFER_UNSUPPORTED");
  225. throw new Error("Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED");
  226. case 0x8CDB:
  227. console.error("Incomplete: FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER from ext. Or Safari/iOS undefined behaviour.");
  228. break;
  229. default:
  230. console.error("incomplete framebuffer", status);
  231. console.log(this);
  232. throw new Error("Incomplete framebuffer: " + status);
  233. }
  234. }
  235.  
  236. setFilter(filter)
  237. {
  238. this.texture.filter = filter;
  239. this.texture.setSize(this.width, this.height);
  240. }
  241.  
  242. setCamPos(camPos)
  243. {
  244. this.camPos = camPos || this.camPos;
  245. }
  246.  
  247. setMatrices(M, V, P)
  248. {
  249. this._modelMatrix = M || this._modelMatrix;
  250. this._viewMatrix = V || this._viewMatrix;
  251. this._projectionMatrix = P || this._projectionMatrix;
  252. }
  253.  
  254. renderStart()
  255. {
  256. this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_CUBE_MAP, this.texture.tex);
  257. this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._framebuffer);
  258. this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, this._depthbuffer);
  259. this._cgl.gl.viewport(0, 0, this.width, this.height);
  260. this._cgl.pushGlFrameBuffer(this._framebuffer);
  261. this._cgl.pushFrameBuffer(this);
  262. }
  263.  
  264. renderStartCubemapFace(index)
  265. {
  266. this._cgl.pushModelMatrix();
  267. this._cgl.pushViewMatrix();
  268. this._cgl.pushPMatrix();
  269.  
  270. this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cubemapProperties[index].face, this.texture.tex, 0);
  271. this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.RENDERBUFFER, this._depthbuffer);
  272.  
  273. if (this._options.clear)
  274. {
  275. this._cgl.gl.clearColor(0, 0, 0, 1);
  276. this._cgl.gl.clear(this._cgl.gl.COLOR_BUFFER_BIT | this._cgl.gl.DEPTH_BUFFER_BIT);
  277. }
  278.  
  279. this.setMatricesCubemapFace(index);
  280. }
  281.  
  282. setMatricesCubemapFace(index)
  283. {
  284. mat4.copy(this._cgl.mMatrix, this._modelMatrix);
  285. vec3.add(this._lookAtTemp, this.camPos, this._cubemapProperties[index].lookAt);
  286.  
  287. mat4.lookAt(this._cgl.vMatrix, this.camPos, this._lookAtTemp, this._cubemapProperties[index].up); // V
  288.  
  289. mat4.copy(this._cgl.pMatrix, this._projectionMatrix);
  290. }
  291.  
  292. renderEndCubemapFace()
  293. {
  294. this._cgl.popPMatrix();
  295. this._cgl.popModelMatrix();
  296. this._cgl.popViewMatrix();
  297. }
  298.  
  299. renderEnd()
  300. {
  301. this._cgl.profileData.profileFramebuffer++;
  302.  
  303. if (this._cgl.glVersion !== 1)
  304. {
  305. this._cgl.gl.bindFramebuffer(this._cgl.gl.READ_FRAMEBUFFER, this._framebuffer);
  306. // this._cgl.gl.bindFramebuffer(this._cgl.gl.DRAW_FRAMEBUFFER, this._textureFrameBuffer);
  307. // * NOTE: the line below is commented out because it clears the screen to black after
  308. // * point light shadow map has been rendered
  309. // this._cgl.gl.clearBufferfv(this._cgl.gl.COLOR, 0, [0.0, 0.0, 0.0, 1.0]);
  310. }
  311.  
  312. this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.popGlFrameBuffer());
  313. this._cgl.popFrameBuffer();
  314.  
  315. this._cgl.resetViewPort();
  316. this.updateMipMap();
  317. }
  318.  
  319. updateMipMap()
  320. {
  321. if (!this.texture) return;
  322.  
  323. this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_CUBE_MAP, this.texture.tex);
  324. this.texture.updateMipMap();
  325. this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_CUBE_MAP, null);
  326. }
  327. }
  328.  
  329. export { CubemapFramebuffer };