cione-comp-lib
Version:
`$ yarn add cione-comp-lib` 或者 `$ npm i cione-comp-lib -S`
250 lines (249 loc) • 9.67 kB
JavaScript
import Base from "./core/Base.mjs";
import Texture from "./Texture.mjs";
import glenum from "./core/glenum.mjs";
import Cache from "./core/Cache.mjs";
var KEY_FRAMEBUFFER = "framebuffer";
var KEY_RENDERBUFFER = "renderbuffer";
var KEY_RENDERBUFFER_WIDTH = KEY_RENDERBUFFER + "_width";
var KEY_RENDERBUFFER_HEIGHT = KEY_RENDERBUFFER + "_height";
var KEY_RENDERBUFFER_ATTACHED = KEY_RENDERBUFFER + "_attached";
var KEY_DEPTHTEXTURE_ATTACHED = "depthtexture_attached";
var GL_FRAMEBUFFER = glenum.FRAMEBUFFER;
var GL_RENDERBUFFER = glenum.RENDERBUFFER;
var GL_DEPTH_ATTACHMENT = glenum.DEPTH_ATTACHMENT;
var GL_COLOR_ATTACHMENT0 = glenum.COLOR_ATTACHMENT0;
var FrameBuffer = Base.extend(
{
depthBuffer: true,
viewport: null,
_width: 0,
_height: 0,
_textures: null,
_boundRenderer: null
},
function() {
this._cache = new Cache();
this._textures = {};
},
{
getTextureWidth: function() {
return this._width;
},
getTextureHeight: function() {
return this._height;
},
bind: function(renderer) {
if (renderer.__currentFrameBuffer) {
if (renderer.__currentFrameBuffer === this) {
return;
}
console.warn("Renderer already bound with another framebuffer. Unbind it first");
}
renderer.__currentFrameBuffer = this;
var _gl = renderer.gl;
_gl.bindFramebuffer(GL_FRAMEBUFFER, this._getFrameBufferGL(renderer));
this._boundRenderer = renderer;
var cache = this._cache;
cache.put("viewport", renderer.viewport);
var hasTextureAttached = false;
var width;
var height;
for (var attachment in this._textures) {
hasTextureAttached = true;
var obj = this._textures[attachment];
if (obj) {
width = obj.texture.width;
height = obj.texture.height;
this._doAttach(renderer, obj.texture, attachment, obj.target);
}
}
this._width = width;
this._height = height;
if (!hasTextureAttached && this.depthBuffer) {
console.error("Must attach texture before bind, or renderbuffer may have incorrect width and height.");
}
if (this.viewport) {
renderer.setViewport(this.viewport);
} else {
renderer.setViewport(0, 0, width, height, 1);
}
var attachedTextures = cache.get("attached_textures");
if (attachedTextures) {
for (var attachment in attachedTextures) {
if (!this._textures[attachment]) {
var target = attachedTextures[attachment];
this._doDetach(_gl, attachment, target);
}
}
}
if (!cache.get(KEY_DEPTHTEXTURE_ATTACHED) && this.depthBuffer) {
if (cache.miss(KEY_RENDERBUFFER)) {
cache.put(KEY_RENDERBUFFER, _gl.createRenderbuffer());
}
var renderbuffer = cache.get(KEY_RENDERBUFFER);
if (width !== cache.get(KEY_RENDERBUFFER_WIDTH) || height !== cache.get(KEY_RENDERBUFFER_HEIGHT)) {
_gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
_gl.renderbufferStorage(GL_RENDERBUFFER, _gl.DEPTH_COMPONENT16, width, height);
cache.put(KEY_RENDERBUFFER_WIDTH, width);
cache.put(KEY_RENDERBUFFER_HEIGHT, height);
_gl.bindRenderbuffer(GL_RENDERBUFFER, null);
}
if (!cache.get(KEY_RENDERBUFFER_ATTACHED)) {
_gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
cache.put(KEY_RENDERBUFFER_ATTACHED, true);
}
}
},
unbind: function(renderer) {
renderer.__currentFrameBuffer = null;
var _gl = renderer.gl;
_gl.bindFramebuffer(GL_FRAMEBUFFER, null);
this._boundRenderer = null;
this._cache.use(renderer.__uid__);
var viewport = this._cache.get("viewport");
if (viewport) {
renderer.setViewport(viewport);
}
this.updateMipmap(renderer);
},
updateMipmap: function(renderer) {
var _gl = renderer.gl;
for (var attachment in this._textures) {
var obj = this._textures[attachment];
if (obj) {
var texture = obj.texture;
if (!texture.NPOT && texture.useMipmap && texture.minFilter === Texture.LINEAR_MIPMAP_LINEAR) {
var target = texture.textureType === "textureCube" ? glenum.TEXTURE_CUBE_MAP : glenum.TEXTURE_2D;
_gl.bindTexture(target, texture.getWebGLTexture(renderer));
_gl.generateMipmap(target);
_gl.bindTexture(target, null);
}
}
}
},
checkStatus: function(_gl) {
return _gl.checkFramebufferStatus(GL_FRAMEBUFFER);
},
_getFrameBufferGL: function(renderer) {
var cache = this._cache;
cache.use(renderer.__uid__);
if (cache.miss(KEY_FRAMEBUFFER)) {
cache.put(KEY_FRAMEBUFFER, renderer.gl.createFramebuffer());
}
return cache.get(KEY_FRAMEBUFFER);
},
attach: function(texture, attachment, target) {
if (!texture.width) {
throw new Error("The texture attached to color buffer is not a valid.");
}
attachment = attachment || GL_COLOR_ATTACHMENT0;
target = target || glenum.TEXTURE_2D;
var boundRenderer = this._boundRenderer;
var _gl = boundRenderer && boundRenderer.gl;
var attachedTextures;
if (_gl) {
var cache = this._cache;
cache.use(boundRenderer.__uid__);
attachedTextures = cache.get("attached_textures");
}
var previous = this._textures[attachment];
if (previous && previous.target === target && previous.texture === texture && (attachedTextures && attachedTextures[attachment] != null)) {
return;
}
var canAttach = true;
if (boundRenderer) {
canAttach = this._doAttach(boundRenderer, texture, attachment, target);
if (!this.viewport) {
boundRenderer.setViewport(0, 0, texture.width, texture.height, 1);
}
}
if (canAttach) {
this._textures[attachment] = this._textures[attachment] || {};
this._textures[attachment].texture = texture;
this._textures[attachment].target = target;
}
},
_doAttach: function(renderer, texture, attachment, target) {
var _gl = renderer.gl;
var webglTexture = texture.getWebGLTexture(renderer);
var attachedTextures = this._cache.get("attached_textures");
if (attachedTextures && attachedTextures[attachment]) {
var obj = attachedTextures[attachment];
if (obj.texture === texture && obj.target === target) {
return;
}
}
attachment = +attachment;
var canAttach = true;
if (attachment === GL_DEPTH_ATTACHMENT || attachment === glenum.DEPTH_STENCIL_ATTACHMENT) {
var extension = renderer.getGLExtension("WEBGL_depth_texture");
if (!extension) {
console.error("Depth texture is not supported by the browser");
canAttach = false;
}
if (texture.format !== glenum.DEPTH_COMPONENT && texture.format !== glenum.DEPTH_STENCIL) {
console.error("The texture attached to depth buffer is not a valid.");
canAttach = false;
}
if (canAttach) {
var renderbuffer = this._cache.get(KEY_RENDERBUFFER);
if (renderbuffer) {
_gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, null);
_gl.deleteRenderbuffer(renderbuffer);
this._cache.put(KEY_RENDERBUFFER, false);
}
this._cache.put(KEY_RENDERBUFFER_ATTACHED, false);
this._cache.put(KEY_DEPTHTEXTURE_ATTACHED, true);
}
}
_gl.framebufferTexture2D(GL_FRAMEBUFFER, attachment, target, webglTexture, 0);
if (!attachedTextures) {
attachedTextures = {};
this._cache.put("attached_textures", attachedTextures);
}
attachedTextures[attachment] = attachedTextures[attachment] || {};
attachedTextures[attachment].texture = texture;
attachedTextures[attachment].target = target;
return canAttach;
},
_doDetach: function(_gl, attachment, target) {
_gl.framebufferTexture2D(GL_FRAMEBUFFER, attachment, target, null, 0);
var attachedTextures = this._cache.get("attached_textures");
if (attachedTextures && attachedTextures[attachment]) {
attachedTextures[attachment] = null;
}
if (attachment === GL_DEPTH_ATTACHMENT || attachment === glenum.DEPTH_STENCIL_ATTACHMENT) {
this._cache.put(KEY_DEPTHTEXTURE_ATTACHED, false);
}
},
detach: function(attachment, target) {
this._textures[attachment] = null;
if (this._boundRenderer) {
var cache = this._cache;
cache.use(this._boundRenderer.__uid__);
this._doDetach(this._boundRenderer.gl, attachment, target);
}
},
dispose: function(renderer) {
var _gl = renderer.gl;
var cache = this._cache;
cache.use(renderer.__uid__);
var renderBuffer = cache.get(KEY_RENDERBUFFER);
if (renderBuffer) {
_gl.deleteRenderbuffer(renderBuffer);
}
var frameBuffer = cache.get(KEY_FRAMEBUFFER);
if (frameBuffer) {
_gl.deleteFramebuffer(frameBuffer);
}
cache.deleteContext(renderer.__uid__);
this._textures = {};
}
}
);
FrameBuffer.DEPTH_ATTACHMENT = GL_DEPTH_ATTACHMENT;
FrameBuffer.COLOR_ATTACHMENT0 = GL_COLOR_ATTACHMENT0;
FrameBuffer.STENCIL_ATTACHMENT = glenum.STENCIL_ATTACHMENT;
FrameBuffer.DEPTH_STENCIL_ATTACHMENT = glenum.DEPTH_STENCIL_ATTACHMENT;
var FrameBuffer$1 = FrameBuffer;
export { FrameBuffer$1 as default };