cables_dev/cables/src/core/cgl/cgl_framebuffer.js
import { Logger } from "cables-shared-client";
import { Texture } from "./cgl_texture.js";
// todo: convert to prototyped...
/**
* a framebuffer
* @constructor
* @class
* @constructs Framebuffer
* @param {Context} _cgl cgl
* @param {Number} _w width
* @param {Number} _h height
* @param {Object} options
*/
const Framebuffer = function (_cgl, _w, _h, options)
{
const cgl = _cgl;
this._log = new Logger("Framebuffer");
this.valid = true;
let depthTextureExt = cgl.gl.DEPTH_TEXTURE;
if (!depthTextureExt) depthTextureExt = cgl.enableExtension("WEBGL_depth_texture");
if (!depthTextureExt) depthTextureExt = cgl.enableExtension("WEBKIT_WEBGL_depth_texture");
if (!depthTextureExt) depthTextureExt = cgl.enableExtension("MOZ_WEBGL_depth_texture");
if (!depthTextureExt)
{
this._log.error("NO_DEPTH_TEXTURE", "no depth texture support");
return;
}
let width = _w || 512;
let height = _h || 512;
options = options || {
"isFloatingPointTexture": false,
};
if (!options.hasOwnProperty("clear")) options.clear = true;
if (!options.hasOwnProperty("filter")) options.filter = Texture.FILTER_LINEAR;
const texture = new Texture(cgl, {
"isFloatingPointTexture": options.isFloatingPointTexture,
"filter": options.filter,
"wrap": options.wrap || Texture.CLAMP_TO_EDGE
});
let textureDepth = null;
if (depthTextureExt)
{
textureDepth = new Texture(cgl, {
"isDepthTexture": true,
});
}
this._options = options;
const frameBuf = cgl.gl.createFramebuffer();
const depthBuffer = cgl.gl.createRenderbuffer();
this.getWidth = function ()
{
return width;
};
this.getHeight = function ()
{
return height;
};
/**
* get native gl framebuffer
* @function getGlFrameBuffer
* @memberof Framebuffer
* @returns {Object} framebuffer
*/
this.getGlFrameBuffer = function ()
{
return frameBuf;
};
/**
* get depth renderbuffer
* @function getDepthRenderBuffer
* @memberof Framebuffer
* @returns {Object} renderbuffer
*/
this.getDepthRenderBuffer = function ()
{
return depthBuffer;
};
/**
* get color texture
* @function getTextureColor
* @memberof Framebuffer
* @returns {Texture} rgba texture
*/
this.getTextureColor = function ()
{
return texture;
};
/**
* get depth texture
* @function getTextureDepth
* @memberof Framebuffer
* @returns {Texture} depth texture
*/
this.getTextureDepth = function ()
{
return textureDepth;
};
this.setFilter = function (f)
{
texture.filter = f;
texture.setSize(width, height);
};
this.setSize = function (w, h)
{
if (w < 2) w = 2;
if (h < 2) h = 2;
width = Math.ceil(w);
height = Math.ceil(h);
cgl.profileData.profileFrameBuffercreate++;
cgl.gl.bindFramebuffer(cgl.gl.FRAMEBUFFER, frameBuf);
cgl.gl.bindRenderbuffer(cgl.gl.RENDERBUFFER, depthBuffer);
texture.setSize(width, height);
if (textureDepth) textureDepth.setSize(width, height);
// if(depthTextureExt) cgl.gl.renderbufferStorage(cgl.gl.RENDERBUFFER, cgl.gl.DEPTH_COMPONENT16, width,height);
if (depthTextureExt) cgl.gl.renderbufferStorage(cgl.gl.RENDERBUFFER, cgl.gl.DEPTH_COMPONENT16, width, height);
cgl.gl.framebufferTexture2D(cgl.gl.FRAMEBUFFER, cgl.gl.COLOR_ATTACHMENT0, cgl.gl.TEXTURE_2D, texture.tex, 0);
if (depthTextureExt)
{
cgl.gl.framebufferRenderbuffer(cgl.gl.FRAMEBUFFER, cgl.gl.DEPTH_ATTACHMENT, cgl.gl.RENDERBUFFER, depthBuffer);
cgl.gl.framebufferTexture2D(
cgl.gl.FRAMEBUFFER,
cgl.gl.DEPTH_ATTACHMENT, // safari needs DEPTH_ATTACHMENT NOT DEPTH_ATTACHMENT16
// cgl.gl.DEPTH_COMPONENT16,
cgl.gl.TEXTURE_2D,
textureDepth.tex,
0,
);
}
if (!cgl.gl.isFramebuffer(frameBuf)) throw new Error("Invalid framebuffer");
const status = cgl.gl.checkFramebufferStatus(cgl.gl.FRAMEBUFFER);
switch (status)
{
case cgl.gl.FRAMEBUFFER_COMPLETE:
break;
case cgl.gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
this._log.warn("FRAMEBUFFER_INCOMPLETE_ATTACHMENT...", width, height, texture.tex, depthBuffer);
this.valid = false;
throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
case cgl.gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
this._log.warn("FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
this.valid = false;
throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
case cgl.gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
this._log.warn("FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
this.valid = false;
throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
case cgl.gl.FRAMEBUFFER_UNSUPPORTED:
this._log.warn("FRAMEBUFFER_UNSUPPORTED");
this.valid = false;
this._log.warn(width, height, options);
throw new Error("Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED");
case 0x8CDB:
this._log.warn("Incomplete: FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER from ext. Or Safari/iOS undefined behaviour.");
this.valid = false;
break;
default:
this._log.warn("incomplete framebuffer", status);
this.valid = false;
throw new Error("Incomplete framebuffer: " + status);
}
cgl.gl.bindTexture(cgl.gl.TEXTURE_2D, null);
cgl.gl.bindRenderbuffer(cgl.gl.RENDERBUFFER, null);
cgl.gl.bindFramebuffer(cgl.gl.FRAMEBUFFER, null);
};
this.renderStart = function ()
{
cgl.pushModelMatrix();
cgl.gl.bindFramebuffer(cgl.gl.FRAMEBUFFER, frameBuf);
cgl.pushGlFrameBuffer(frameBuf);
cgl.pushFrameBuffer(this);
cgl.pushPMatrix();
cgl.gl.viewport(0, 0, width, height);
if (this._options.clear)
{
cgl.gl.clearColor(0, 0, 0, 0);
cgl.gl.clear(cgl.gl.COLOR_BUFFER_BIT | cgl.gl.DEPTH_BUFFER_BIT);
}
};
this.renderEnd = function ()
{
cgl.popPMatrix();
cgl.gl.bindFramebuffer(cgl.gl.FRAMEBUFFER, cgl.popGlFrameBuffer());
cgl.popFrameBuffer();
cgl.popModelMatrix();
cgl.resetViewPort();
};
this.delete = function ()
{
texture.delete();
this.valid = false;
if (textureDepth) textureDepth.delete();
cgl.gl.deleteRenderbuffer(depthBuffer);
cgl.gl.deleteFramebuffer(frameBuf);
};
this.dispose = this.delete;
this.setSize(width, height);
};
export { Framebuffer };