@awayjs/stage
Version:
Stage for AwayJS
200 lines (199 loc) • 9.51 kB
JavaScript
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 };