UNPKG

@awayjs/stage

Version:
200 lines (199 loc) 9.51 kB
import { SamplerStateWebGL } from './SamplerStateWebGL'; import { RenderTargetWebGL } from './RenderTargetWebGL'; import { RenderTargetWebGLMSAA } from './RenderTargetWebGLMSAA'; import * as GL_MAP from './ConstantsWebGL'; var TextureContextWebGL = /** @class */ (function () { function TextureContextWebGL(_context) { this._context = _context; this._samplerStates = []; this._currentRT = null; var gl = this._gl = _context._gl; // for some devices there are bug when we use MAX samples, but ok when use MAX - 1 TextureContextWebGL.MAX_SAMPLERS = Math.min(TextureContextWebGL.MAX_SAMPLERS, gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS) - 1); //defaults for (var i = 0; i < TextureContextWebGL.MAX_SAMPLERS; ++i) { this._samplerStates[i] = new SamplerStateWebGL(i, null, _context); this._samplerStates[i].set(_context.glVersion === 2 ? gl.REPEAT : gl.CLAMP_TO_EDGE, gl.LINEAR, gl.LINEAR); } } TextureContextWebGL.prototype.bindRenderTarget = function (target, check) { if (check === void 0) { check = false; } if (check && this._currentRT === target) return target; var prev = this._currentRT; this._currentRT = target; this._gl.bindFramebuffer(this._gl.FRAMEBUFFER, target ? target._framebuffer : null); return prev; }; TextureContextWebGL.prototype.bindTexture = function (texture, check, target) { if (check === void 0) { check = false; } if (target === void 0) { target = this._gl.TEXTURE_2D; } if (check && texture === this._lastBoundedTexture) return texture; var prev = this._lastBoundedTexture; this._lastBoundedTexture = texture; this._gl.bindTexture(target, texture ? texture._glTexture : texture); return prev; }; TextureContextWebGL.prototype.uploadFromArray = function (target, array, miplevel, premultiplied) { if (miplevel === void 0) { miplevel = 0; } if (premultiplied === void 0) { premultiplied = false; } var gl = this._context._gl; var width = target._width >>> miplevel; var height = target._height >>> miplevel; if (array && array.length !== width * height * 4) { /* eslint-disable-next-line */ throw new Error("Array is not the correct length for texture dimensions: expected: ".concat(width * height * 4, ", exist: ").concat(array.length)); } if (array instanceof Array) array = new Uint8Array(array); // push lastest used texture to stack and bind new var prev = this.bindTexture(target, true, gl.TEXTURE_2D); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplied); gl.texImage2D(gl.TEXTURE_2D, miplevel, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, array); // restore last texture boundings // otherwise we will corrupt state this.bindTexture(prev, true, gl.TEXTURE_2D); }; TextureContextWebGL.prototype.setTextureAt = function (sampler, texture) { var gl = this._context._gl; var samplerState = this._samplerStates[sampler]; var textureType = GL_MAP.TEXTURE[texture.textureType]; if ((texture || samplerState.type)) { gl.activeTexture(gl.TEXTURE0 + sampler); } if (!texture) { if (samplerState.type) { // disable link to sampler in bounded texture if (samplerState.boundedTexture) { samplerState.boundedTexture._state.id = -1; } this.bindTexture(null, false, samplerState.type); samplerState.boundedTexture = null; samplerState.type = null; } return -1; } texture._state.id = sampler; this.bindTexture(texture, false, textureType); samplerState.commit(textureType, texture); return sampler; }; TextureContextWebGL.prototype.setSamplerStateAt = function (sampler, wrap, filter, mipfilter) { if (!this._samplerStates[sampler]) { throw 'Sampler is out of bounds.'; } this._samplerStates[sampler].set(GL_MAP.WRAP[wrap], GL_MAP.FILTER[filter], GL_MAP.MIP_FILTER[filter][mipfilter]); }; TextureContextWebGL.prototype.unsafeCopyToTexture = function (target, rect, destPoint) { var gl = this._context._gl; var prev = this.bindTexture(target, false); gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, destPoint.x, destPoint.y, rect.x, rect.y, rect.width, rect.height); // restore latest active texture this.bindTexture(prev, true); }; TextureContextWebGL.prototype.setRenderToTexture = function (target, enableDepthAndStencil, antiAlias) { if (enableDepthAndStencil === void 0) { enableDepthAndStencil = false; } if (antiAlias === void 0) { antiAlias = true; } if (this._currentRT) { this._currentRT.present(); } this.setFrameBuffer(target, enableDepthAndStencil, antiAlias); }; TextureContextWebGL.prototype.setRenderToBackBuffer = function () { if (this._currentRT) { this._currentRT.present(); } this.bindRenderTarget(null, true); }; /*internal*/ TextureContextWebGL.prototype.setFrameBuffer = function (target, enableDepthAndStencil, antiAlias) { var width = target.width; var height = target.height; if (!target._renderTarget) { this.initFrameBuffer(target, antiAlias, enableDepthAndStencil); } this.bindRenderTarget(target._renderTarget, true); if (enableDepthAndStencil) { this._context.enableDepth(); this._context.enableStencil(); } else { this._context.disableDepth(); this._context.disableStencil(); } this._context.setViewport(0, 0, width, height); }; /*internal*/ TextureContextWebGL.prototype.initFrameBuffer = function (target, antiAlias, depthStencil) { var width = target.width; var height = target.height; var rt = new RenderTargetWebGL(this._context, width, height, !depthStencil); rt.linkTexture(target); // only webgl2 have msaa if (antiAlias && this._context.glVersion === 2) { var msaa = new RenderTargetWebGLMSAA(this._context, width, height, !depthStencil); msaa.linkTarget(rt); rt = msaa; } target._renderTarget = rt; }; /*internal*/ TextureContextWebGL.prototype.presentFrameBufferTo = function (source, target, rect, point) { var gl = this._context._gl; var prefRT = this._currentRT; if (!target._renderTarget) { this.initFrameBuffer(target, false, false); } var targetFrameBuffer = target._renderTarget.drawBuffer; if (!source || !source.isMsaaTarget || gl instanceof WebGLRenderingContext) { // direct copy to target texture. // same as call this._context.renderToTexture // gl.bindFramebuffer(gl.FRAMEBUFFER, source.readBuffer); this.bindRenderTarget(source, true); this.unsafeCopyToTexture(target, rect, point); } else if (targetFrameBuffer) { // bind framebuffer with renderbuffer to READ slot gl.bindFramebuffer(gl.READ_FRAMEBUFFER, source.drawBuffer); // bind framebuffer with texture to WRITE slot gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, targetFrameBuffer); // clear // gl.clearBufferfv(gl.COLOR, 0, [0.0, 0.0, 0.0, 0.0]); // copy renderbuffer to texture gl.blitFramebuffer(rect.x | 0, rect.y | 0, (rect.width + rect.x) | 0, (rect.height + rect.y) | 0, point.x | 0, point.y | 0, (point.x + rect.width) | 0, (point.y + rect.height) | 0, gl.COLOR_BUFFER_BIT, gl.LINEAR); } this.blitTextureToRenderbuffer(target); this.bindRenderTarget(prefRT, true); }; /** * Blit self texture to renderbuffer if a multisampled */ /*internal*/ TextureContextWebGL.prototype.blitTextureToRenderbuffer = function (target) { var gl = this._context._gl; if (!target._renderTarget.isMsaaTarget || !(gl instanceof WebGL2RenderingContext)) { return; } var width = target._width; var height = target._height; // bind framebuffer with renderbuffer to DRAW slot gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, target._renderTarget.readBuffer); // bind framebuffer with texture to READ slot gl.bindFramebuffer(gl.READ_FRAMEBUFFER, target._renderTarget.drawBuffer); // clear // gl.clearBufferfv(gl.COLOR, 0, [0.0, 0.0, 0.0, 0.0]); // copy texture to renderbuffer! gl.blitFramebuffer(0, 0, width, height, 0, 0, width, height, gl.COLOR_BUFFER_BIT, gl.LINEAR); }; /*internal*/ TextureContextWebGL.prototype.disposeTexture = function (texture) { var gl = this._context._gl; if (texture === this._lastBoundedTexture) { this._lastBoundedTexture = null; } gl.deleteTexture(texture._glTexture); if (texture._renderTarget) { texture._renderTarget.dispose(); } }; TextureContextWebGL.MAX_SAMPLERS = 16; return TextureContextWebGL; }()); export { TextureContextWebGL };