@awayjs/stage
Version:
Stage for AwayJS
698 lines (697 loc) • 32.1 kB
JavaScript
import { CoordinateSystem } from '@awayjs/core';
import { ContextGLBlendEquation } from '../base/ContextGLBlendFactor';
import { ContextGLDrawMode } from '../base/ContextGLDrawMode';
import { ContextGLClearMask } from '../base/ContextGLClearMask';
import { ContextGLCompareMode } from '../base/ContextGLCompareMode';
import { ContextGLProgramType } from '../base/ContextGLProgramType';
import { ContextGLStencilAction } from '../base/ContextGLStencilAction';
import { ContextGLTriangleFace } from '../base/ContextGLTriangleFace';
import { CubeTextureWebGL } from './CubeTextureWebGL';
import { IndexBufferWebGL } from './IndexBufferWebGL';
import { ProgramWebGL } from './ProgramWebGL';
import { TextureWebGL } from './TextureWebGL';
import { VertexBufferWebGL } from './VertexBufferWebGL';
import { TextureContextWebGL } from './TextureContextWebGL';
import { VaoContextWebGL, VaoWebGL } from './VaoWebGL';
import { State } from './State';
import { Settings } from '../Settings';
import { FenceContextWebGL } from './FenceContextWebGL';
import * as GL_MAP from './ConstantsWebGL';
import { StatsWebGL } from './StatsWebGL';
var _DEBUG_renderMode = '';
//@ts-ignore
window._AWAY_DEBUG_ = Object.assign(window._AWAY_DEBUG_ || {}, {
forceLineMode: function (lineMode) {
if (lineMode === void 0) { lineMode = false; }
_DEBUG_renderMode = lineMode ? 'line' : '';
}
});
var ContextWebGL = /** @class */ (function () {
function ContextWebGL(canvas, alpha) {
if (alpha === void 0) { alpha = false; }
this.stats = new StatsWebGL();
this._drawing = true;
// [x, y, w, h]
this._viewportState = new State(0, 0, 0, 0);
// [enable, func, funcA, src, dst, srcA, dstA];
this._blendState = new State(0, GL_MAP.BLEND_EQ[ContextGLBlendEquation.ADD], GL_MAP.BLEND_EQ[ContextGLBlendEquation.ADD], 0, 0, -1, -1);
// [r, g, b, a]
this._colorMapState = new State(true, true, true, true);
// [r, g, b, a]
this._clearColorState = new State(0, 0, 0, 0);
// [stencil, depth], i don't know default a depth value, set -1, to force change it
this._clearSD = new State(0, -1);
// [enable, mask, func]
this._depthState = new State(0, 0, 0);
// [enable, mask, func]
this._stencilState = new State(0, 1, 0);
// [enable, face]
this._cullState = new State(0, 0, 0);
this._stencilReferenceValue = 0;
this._stencilReadMask = 0xff;
this._separateStencil = false;
this._lastBoundedIndexBuffer = null;
this._hasVao = false;
this._instancedEnabled = false;
this._instancesCount = 1;
this._container = canvas;
this.initWebGL(alpha);
}
ContextWebGL.prototype.hasInstancing = function () {
return (this._gl instanceof self.WebGL2RenderingContext) || !!this._angleInstanced;
};
Object.defineProperty(ContextWebGL.prototype, "hasFence", {
get: function () {
return !!this._fenceContext;
},
enumerable: false,
configurable: true
});
Object.defineProperty(ContextWebGL.prototype, "hasVao", {
get: function () {
return this._hasVao;
},
enumerable: false,
configurable: true
});
Object.defineProperty(ContextWebGL.prototype, "glVersion", {
get: function () {
return this._glVersion;
},
enumerable: false,
configurable: true
});
Object.defineProperty(ContextWebGL.prototype, "pixelRatio", {
get: function () {
return this._pixelRatio;
},
set: function (v) {
this._pixelRatio = v;
},
enumerable: false,
configurable: true
});
Object.defineProperty(ContextWebGL.prototype, "container", {
get: function () {
return this._container;
},
set: function (value) {
this._container = value;
this.initWebGL();
},
enumerable: false,
configurable: true
});
Object.defineProperty(ContextWebGL.prototype, "standardDerivatives", {
get: function () {
return this._standardDerivatives;
},
enumerable: false,
configurable: true
});
ContextWebGL.prototype.assertLost = function (when) {
if (!Settings.PROFILE_CONTEXT_LOST) {
return;
}
if (this._gl.isContextLost()) {
throw "[ContextWebGL] Context lost after ".concat(when, ", state: ").concat(this.stats.toString());
}
};
ContextWebGL.prototype.initWebGL = function (alpha) {
if (alpha === void 0) { alpha = false; }
var props = {
alpha: alpha,
antialias: Settings.ENABLE_ANTIALIAS,
stencil: true
};
try {
if (Settings.PREF_WEBGL_VERSION === 2) {
this._gl = this._container.getContext('webgl2', props);
this._glVersion = 2;
}
if (!this._gl) {
this._gl = (this._container.getContext('webgl', props)
|| this._container.getContext('experimental-webgl', props));
this._glVersion = 1;
if (Settings.PREF_WEBGL_VERSION === 2) {
console.warn('[CONTEXT] Preferred WebGL2 not supported on you device. WebGL1 will used!');
}
}
console.debug("[CONTEXT] Preferred WebGL: ".concat(Settings.PREF_WEBGL_VERSION, ", used: ").concat(this._glVersion));
}
catch (e) {
//
}
if (this._gl) {
var gl = this._gl;
this._standardDerivatives = this._glVersion === 2 || !!gl.getExtension('OES_standard_derivatives');
this._stencilCompareMode = gl.ALWAYS;
this._stencilCompareModeBack = gl.ALWAYS;
this._stencilCompareModeFront = gl.ALWAYS;
this._pixelRatio = self.devicePixelRatio || 1;
}
else {
alert('WebGL is not available.');
}
this._texContext = new TextureContextWebGL(this);
if (Settings.ENABLE_VAO) {
if (VaoContextWebGL.isSupported(this._gl)) {
this._vaoContext = new VaoContextWebGL(this);
this._hasVao = true;
}
else {
console.warn('[ContextWebGL] VAO isn\'t supported');
}
}
else {
console.debug('[ContextWebGL] Vao disabled by settings \'ENABLE_VAO\'');
}
if (Settings.ENABLE_ASYNC_READ) {
if (FenceContextWebGL.isSupported(this._gl)) {
this._fenceContext = new FenceContextWebGL(this);
}
else {
console.warn('[ContextWebGL] FenceSync isn\'t supported');
}
}
else {
console.debug('[ContextWebGL] FenceSync disabled by settings \'ENABLE_ASYNC_READ\'');
}
if (this._glVersion === 1) {
this._angleInstanced = this._gl.getExtension('ANGLE_instanced_arrays');
}
// first locked state 0,0,0,0
this._blendState.lock(true);
//@ts-ignore
window._AWAY_CONTEXT_STATS_ = this.stats;
};
ContextWebGL.prototype.gl = function () {
return this._gl;
};
ContextWebGL.prototype.clear = function (red, green, blue, alpha, depth, stencil, mask) {
if (red === void 0) { red = 0; }
if (green === void 0) { green = 0; }
if (blue === void 0) { blue = 0; }
if (alpha === void 0) { alpha = 1; }
if (depth === void 0) { depth = 1; }
if (stencil === void 0) { stencil = 0; }
if (mask === void 0) { mask = ContextGLClearMask.ALL; }
this.stateChangeCallback && this.stateChangeCallback('clear');
if (!this._drawing) {
this.updateBlendStatus();
this._drawing = true;
}
var glmask = 0;
if (mask & ContextGLClearMask.COLOR) {
if (this._clearColorState.set(red, green, blue, alpha)) {
this._gl.clearColor(red, green, blue, alpha);
}
glmask |= this._gl.COLOR_BUFFER_BIT;
}
if (mask & ContextGLClearMask.STENCIL) {
glmask |= this._gl.STENCIL_BUFFER_BIT;
this._clearSD.setAt(0, stencil) && this._gl.clearStencil(stencil);
}
if (mask & ContextGLClearMask.DEPTH) {
glmask |= this._gl.DEPTH_BUFFER_BIT;
this._clearSD.setAt(0, depth) && this._gl.clearDepth(depth);
}
this._gl.clear(glmask);
};
ContextWebGL.prototype.configureBackBuffer = function (width, height, antiAlias, enableDepthAndStencil) {
if (enableDepthAndStencil === void 0) { enableDepthAndStencil = true; }
this.stateChangeCallback && this.stateChangeCallback('setBackBuffer');
this._width = width * this._pixelRatio;
this._height = height * this._pixelRatio;
if (enableDepthAndStencil) {
this.enableStencil();
this.enableDepth();
}
else {
this.disableStencil();
this.disableDepth();
}
if (this._viewportState.set(0, 0, this._width, this._height)) {
this._gl.viewport(0, 0, this._width, this._height);
}
};
ContextWebGL.prototype.createCubeTexture = function (size, _format, _optimizeForRenderToTexture, _streamingLevels) {
if (_streamingLevels === void 0) { _streamingLevels = 0; }
return new CubeTextureWebGL(this, size);
};
ContextWebGL.prototype.createIndexBuffer = function (numIndices) {
return IndexBufferWebGL.create(this, numIndices);
};
ContextWebGL.prototype.createProgram = function () {
return new ProgramWebGL(this);
};
ContextWebGL.prototype.createTexture = function (width, height, _format, _optimizeForRenderToTexture, _streamingLevels) {
if (_streamingLevels === void 0) { _streamingLevels = 0; }
//TODO streaming -- not supported on WebGL
return TextureWebGL.create(this, width, height);
};
ContextWebGL.prototype.createVertexBuffer = function (numVertices, dataPerVertex) {
return VertexBufferWebGL.create(this, numVertices, dataPerVertex);
};
ContextWebGL.prototype.createVao = function () {
if (!this._hasVao)
throw 'VAO isn\'n supported';
return new VaoWebGL(this);
};
ContextWebGL.prototype.dispose = function () {
//
};
ContextWebGL.prototype.drawToBitmapImage2D = function (destination, invalidate, async) {
if (invalidate === void 0) { invalidate = true; }
if (async === void 0) { async = false; }
this.stateChangeCallback && this.stateChangeCallback('drawToBitmap');
var pixels = new Uint8Array(destination.getDataInternal(true, true).buffer);
var rt = this._texContext._currentRT;
var fence = this._fenceContext;
var width = destination.width, height = destination.height;
var promise;
if (async && !fence) {
promise = Promise.resolve(false);
}
var currentRT = this._texContext._currentRT;
if (rt.isMsaaTarget) {
// because RT is MSAA, we should blit it to no-MSAA and use noMSAA framebufer for reading
rt.present();
this._gl.bindFramebuffer(this._gl.FRAMEBUFFER, rt.readBuffer);
}
if (async && fence) {
// tasking a PBO read async
// http://www.songho.ca/opengl/gl_pbo.html
promise = fence
.readPixels(0, 0, width, height)
.then(function (pbo) {
pbo.read(pixels);
if (invalidate) {
destination.invalidateGPU();
}
// restore PBO to fence pool
// but we can destroy it too
fence.release(pbo);
return true;
});
}
else {
// we MUST unbound all bounded PIXEL_PACK buffer to avoid warnings
if (fence) {
fence.unboundAll();
}
// no support or not required as async, use sync operation
this._gl.readPixels(0, 0, width, height, this._gl.RGBA, this._gl.UNSIGNED_BYTE, pixels);
if (invalidate) {
destination.invalidateGPU();
}
}
// restore back buffer bounding to draw framebufer, but only for sync opps
// if (rt.isMsaaTarget && !async) {
this._texContext.bindRenderTarget(currentRT, false);
// }
// for any case return a promise, nut for sync it will be undef;
return promise;
};
/**
* Begin instanced rendering, can't be disabled until drawArrays or drawElements will called
* @param count Count of instances that will be rendered
*/
ContextWebGL.prototype.beginInstancedRender = function (count) {
if (count === void 0) { count = 1; }
if (!this.hasInstancing()) {
throw 'Instanced rendering not supported';
}
this._instancedEnabled = true;
this._instancesCount = count;
};
ContextWebGL.prototype.drawIndices = function (mode, indexBuffer, firstIndex, numIndices) {
if (firstIndex === void 0) { firstIndex = 0; }
if (numIndices === void 0) { numIndices = -1; }
this.stateChangeCallback && this.stateChangeCallback('drawIndices');
var gl = this._gl;
if (!this._drawing)
throw 'Need to clear before drawing if the buffer has not been cleared since the last present() call.';
// updata blend before draw, because blend state can mutated a more times
// reduce a state changes
this.updateBlendStatus();
// so, if we delete the buffer, and then try to compare last bounded buffer - it will valid, because
// because reverence is same
// reset buffer when it not a buffer
if (this._lastBoundedIndexBuffer && !this._lastBoundedIndexBuffer.glBuffer) {
this._lastBoundedIndexBuffer = null;
}
// check, that VAO not bounded
// VAO store index buffer inself
if (!this._hasVao || !this._vaoContext._lastBoundedVao) {
if (this._lastBoundedIndexBuffer !== indexBuffer) {
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer.glBuffer);
}
this._lastBoundedIndexBuffer = indexBuffer;
}
mode = _DEBUG_renderMode === 'line' ? ContextGLDrawMode.LINES : mode;
var glMode = GL_MAP.DRAW_MODE[mode];
var count = (numIndices == -1) ? indexBuffer.numIndices : numIndices;
var type = gl.UNSIGNED_SHORT;
var offset = firstIndex * 2;
var instances = this._instancesCount;
if (!this._instancedEnabled) {
gl.drawElements(glMode, count, type, offset);
}
else if (this._angleInstanced) {
this._angleInstanced.drawElementsInstancedANGLE(glMode, count, type, offset, instances);
}
else {
gl.drawElementsInstanced(glMode, count, type, offset, instances);
}
this._instancedEnabled = false;
this._instancesCount = 1;
this.assertLost('drawElements');
};
ContextWebGL.prototype.bindIndexBuffer = function (indexBuffer) {
this.stateChangeCallback && this.stateChangeCallback('bindIndexBuffer');
this._gl.bindBuffer(this._gl.ELEMENT_ARRAY_BUFFER, indexBuffer.glBuffer);
this._lastBoundedIndexBuffer = indexBuffer;
};
ContextWebGL.prototype.drawVertices = function (mode, firstVertex, numVertices) {
if (firstVertex === void 0) { firstVertex = 0; }
if (numVertices === void 0) { numVertices = -1; }
if (!this._drawing)
throw 'Need to clear before drawing if the buffer has not been cleared since the last present() call.';
this.stateChangeCallback && this.stateChangeCallback('drawVertices');
if (numVertices == 0)
return;
// updata blend before draw, because blend state can mutated a more times
// reduce a state changes
this.updateBlendStatus();
mode = _DEBUG_renderMode === 'line' ? ContextGLDrawMode.LINES : mode;
var glMode = GL_MAP.DRAW_MODE[mode];
var instances = this._instancesCount;
if (!this._instancedEnabled) {
this._gl.drawArrays(glMode, firstVertex, numVertices);
}
else if (this._angleInstanced) {
this._angleInstanced.drawArraysInstancedANGLE(glMode, firstVertex, numVertices, instances);
}
else {
this._gl.drawArraysInstanced(glMode, firstVertex, numVertices, instances);
}
this._instancedEnabled = false;
this._instancesCount = 1;
this.assertLost('drawArrays');
};
ContextWebGL.prototype.present = function () {
this.stateChangeCallback && this.stateChangeCallback('present');
//this._drawing = false;
this._fenceContext && this._fenceContext.tick();
};
ContextWebGL.prototype.setBlendState = function (enable) {
this.stateChangeCallback && this.stateChangeCallback('setBlendState');
this._blendState.setAt(0, +enable);
};
ContextWebGL.prototype.setBlendEquation = function (equationRGB, equationA) {
if (equationA === void 0) { equationA = equationRGB; }
this._blendState.setAt(1, GL_MAP.BLEND_EQ[equationRGB]);
this._blendState.setAt(2, GL_MAP.BLEND_EQ[equationA]);
};
ContextWebGL.prototype.setBlendFactors = function (sourceFactor, destinationFactor, sourceAlphaFactor, destinationAlphaFactor) {
this.stateChangeCallback && this.stateChangeCallback('setBlendFactors');
var src = GL_MAP.BLEND_OP[sourceFactor];
var dst = GL_MAP.BLEND_OP[destinationFactor];
var gl = this._gl;
if (sourceAlphaFactor == void 0) {
// disable separated mode
this._blendState.set(+true, gl.FUNC_ADD, gl.FUNC_ADD, src, dst, -1, -1);
}
else {
if (typeof sourceAlphaFactor !== typeof destinationAlphaFactor) {
// eslint-disable-next-line max-len
throw '[Context] sourceAlphaFactor and destinationAlphaFactor MUST be BOTH presented for separated blend mode';
}
var srcA = GL_MAP.BLEND_OP[sourceAlphaFactor];
var dstA = GL_MAP.BLEND_OP[destinationAlphaFactor];
// endable seprated mode
this._blendState.set(+true, gl.FUNC_ADD, gl.FUNC_ADD, src, dst, srcA, dstA);
}
};
ContextWebGL.prototype.setColorMask = function (red, green, blue, alpha) {
this.stateChangeCallback && this.stateChangeCallback('setColorMask');
if (this._colorMapState.set(red, green, blue, alpha)) {
this._gl.colorMask(red, green, blue, alpha);
}
};
ContextWebGL.prototype.setCulling = function (triangleFaceToCull, coordinateSystem) {
if (coordinateSystem === void 0) { coordinateSystem = CoordinateSystem.LEFT_HANDED; }
this.stateChangeCallback && this.stateChangeCallback('setCulling');
if (triangleFaceToCull === ContextGLTriangleFace.NONE) {
this._cullState.setAt(0, +false) && this._gl.disable(this._gl.CULL_FACE);
}
else {
this._cullState.setAt(0, +true) && this._gl.enable(this._gl.CULL_FACE);
var face = this.translateTriangleFace(triangleFaceToCull, coordinateSystem);
this._cullState.setAt(1, face) && this._gl.cullFace(face);
}
};
// TODO ContextGLCompareMode
ContextWebGL.prototype.setDepthTest = function (depthMask, passCompareMode) {
this.stateChangeCallback && this.stateChangeCallback('setDepthTest');
var mode = GL_MAP.COMPARE_OP[passCompareMode];
this._depthState.setAt(1, +depthMask) && this._gl.depthMask(depthMask);
this._depthState.setAt(2, mode) && this._gl.depthFunc(mode);
};
ContextWebGL.prototype.setViewport = function (x, y, width, height) {
this.stateChangeCallback && this.stateChangeCallback('setViewport');
if (this._viewportState.set(x, y, width, height)) {
this._gl.viewport(x, y, width, height);
}
};
ContextWebGL.prototype.enableDepth = function () {
this.stateChangeCallback && this.stateChangeCallback('enableDepth');
this._depthState.setAt(0, +true) && this._gl.enable(this._gl.DEPTH_TEST);
};
ContextWebGL.prototype.disableDepth = function () {
this.stateChangeCallback && this.stateChangeCallback('disableDepth');
this._depthState.setAt(0, +false) && this._gl.disable(this._gl.DEPTH_TEST);
};
ContextWebGL.prototype.enableStencil = function () {
this.stateChangeCallback && this.stateChangeCallback('enableStencil');
this._stencilState.setAt(0, +true) && this._gl.enable(this._gl.STENCIL_TEST);
};
ContextWebGL.prototype.disableStencil = function () {
this.stateChangeCallback && this.stateChangeCallback('disableStencil');
this._stencilState.setAt(0, +false) && this._gl.disable(this._gl.STENCIL_TEST);
};
ContextWebGL.prototype.setStencilActions = function (triangleFace, compareMode, actionOnBothPass, actionOnDepthFail, actionOnDepthPassStencilFail, coordinateSystem) {
if (triangleFace === void 0) { triangleFace = ContextGLTriangleFace.FRONT_AND_BACK; }
if (compareMode === void 0) { compareMode = ContextGLCompareMode.ALWAYS; }
if (actionOnBothPass === void 0) { actionOnBothPass = ContextGLStencilAction.KEEP; }
if (actionOnDepthFail === void 0) { actionOnDepthFail = ContextGLStencilAction.KEEP; }
if (actionOnDepthPassStencilFail === void 0) { actionOnDepthPassStencilFail = ContextGLStencilAction.KEEP; }
if (coordinateSystem === void 0) { coordinateSystem = CoordinateSystem.LEFT_HANDED; }
this.stateChangeCallback && this.stateChangeCallback('setStencilActions');
this._separateStencil = triangleFace != ContextGLTriangleFace.FRONT_AND_BACK;
var compareModeGL = GL_MAP.COMPARE_OP[compareMode];
var fail = GL_MAP.STENCIL_ACTION[actionOnDepthPassStencilFail];
var zFail = GL_MAP.STENCIL_ACTION[actionOnDepthFail];
var pass = GL_MAP.STENCIL_ACTION[actionOnBothPass];
if (!this._separateStencil) {
this._stencilCompareMode = compareModeGL;
this._gl.stencilFunc(compareModeGL, this._stencilReferenceValue, this._stencilReadMask);
this._gl.stencilOp(fail, zFail, pass);
}
else if (triangleFace == ContextGLTriangleFace.BACK) {
this._stencilCompareModeBack = compareModeGL;
this._gl.stencilFuncSeparate(this._gl.BACK, compareModeGL, this._stencilReferenceValue, this._stencilReadMask);
this._gl.stencilOpSeparate(this._gl.BACK, fail, zFail, pass);
}
else if (triangleFace == ContextGLTriangleFace.FRONT) {
this._stencilCompareModeFront = compareModeGL;
this._gl.stencilFuncSeparate(this._gl.FRONT, compareModeGL, this._stencilReferenceValue, this._stencilReadMask);
this._gl.stencilOpSeparate(this._gl.FRONT, fail, zFail, pass);
}
this.assertLost('setStencilActions');
};
ContextWebGL.prototype.setStencilReferenceValue = function (referenceValue, readMask, writeMask) {
if (readMask === void 0) { readMask = 0xFF; }
if (writeMask === void 0) { writeMask = 0xFF; }
this.stateChangeCallback && this.stateChangeCallback('setStencilReferenceValue');
this._stencilReferenceValue = referenceValue;
this._stencilReadMask = readMask;
if (this._separateStencil) {
this._gl.stencilFuncSeparate(this._gl.FRONT, this._stencilCompareModeFront, referenceValue, readMask);
this._gl.stencilFuncSeparate(this._gl.BACK, this._stencilCompareModeBack, referenceValue, readMask);
}
else {
this._gl.stencilFunc(this._stencilCompareMode, referenceValue, readMask);
}
this._gl.stencilMask(writeMask);
this.assertLost('setStencilReferenceValue');
};
ContextWebGL.prototype.setProgram = function (program) {
// kill focus when program is same
if (this._currentProgram === program) {
return;
}
this.stateChangeCallback && this.stateChangeCallback('setProgram');
//TODO decide on construction/reference resposibilities
this._currentProgram = program;
program.focusProgram();
this.assertLost('setProgram');
};
ContextWebGL.prototype.setProgramConstantsFromArray = function (programType, data) {
if (data.length) {
this._currentProgram.uniform4fv(programType, data);
}
};
ContextWebGL.prototype.setScissorRectangle = function (rect) {
this.stateChangeCallback && this.stateChangeCallback('setScissorRectangle');
if (!rect) {
this._gl.disable(this._gl.SCISSOR_TEST);
return;
}
var isRT = !!this._texContext._currentRT;
// for framebuffer we use framebuffer size without internal scale
var pr = isRT ? 1 : this._pixelRatio;
/*
// not require flip when renderer to RT, because already flipped
const targetY = isRT
? rect.y
: this._height - (rect.y + rect.height) * pr;
*/
this._gl.enable(this._gl.SCISSOR_TEST);
this._gl.scissor(rect.x * pr, rect.y * pr, rect.width * pr, rect.height * pr);
this.assertLost('scissor');
};
ContextWebGL.prototype.setTextureAt = function (sampler, texture) {
this.stateChangeCallback && this.stateChangeCallback('setTextureAt');
var id = this._texContext.setTextureAt(sampler, texture);
// id - is real sampler id, because texture context can change id of sasmpler
// or return -1 when texture unbounded
if (id >= 0) {
this._currentProgram.uniform1i(ContextGLProgramType.SAMPLER, sampler, id);
}
};
ContextWebGL.prototype.setSamplerStateAt = function (sampler, wrap, filter, mipfilter) {
this.stateChangeCallback && this.stateChangeCallback('setSamplerStateAt');
// proxy
this._texContext.setSamplerStateAt(sampler, wrap, filter, mipfilter);
this.assertLost('setSamplerStateAt');
};
ContextWebGL.prototype.setVertexBufferAt = function (index, buffer, bufferOffset, format) {
if (bufferOffset === void 0) { bufferOffset = 0; }
if (format === void 0) { format = 4; }
this.stateChangeCallback && this.stateChangeCallback('setVertexBufferAt');
var location = this._currentProgram ? this._currentProgram.getAttribLocation(index) : -1;
var gl = this._gl;
// when we try bind any buffers without VAO we should unbound VAO
// othwerwithe we bind a buffer to vao instead main contex
if (this.hasVao && this._vaoContext._isRequireUnbound) {
this._vaoContext.unbindVertexArrays();
}
// disable location, OS will fire error when loadings invalid buffer to it
// location - is index of buffer location inside shader
// index - attrib location for binding.
// FOR OSx - IT CAN BE DIFFERENT
if (!buffer) {
if (location > -1) {
gl.disableVertexAttribArray(index);
}
return;
}
//buffer may not have changed if concatenated buffers are being used
if (this._currentArrayBuffer != buffer || (this.hasVao && this._vaoContext._lastBoundedVao)) {
this._currentArrayBuffer = buffer;
gl.bindBuffer(gl.ARRAY_BUFFER, buffer ? buffer.glBuffer : null);
}
var properties = GL_MAP.VERTEX_BUF_PROPS[format];
gl.enableVertexAttribArray(location);
gl.vertexAttribPointer(location, properties.size, properties.type, properties.normalized, buffer.dataPerVertex, bufferOffset);
if (this._instancedEnabled && buffer.instanced) {
if (this._angleInstanced) {
this._angleInstanced.vertexAttribDivisorANGLE(location, 1);
}
else {
gl.vertexAttribDivisor(location, 1);
}
}
this.assertLost('setVertexBufferAt');
};
ContextWebGL.prototype.setRenderToTexture = function (target, enableDepthAndStencil, antiAlias, _surfaceSelector, _mipmapSelector) {
if (enableDepthAndStencil === void 0) { enableDepthAndStencil = false; }
if (antiAlias === void 0) { antiAlias = 0; }
if (_surfaceSelector === void 0) { _surfaceSelector = 0; }
if (_mipmapSelector === void 0) { _mipmapSelector = 0; }
this.stateChangeCallback && this.stateChangeCallback('setRenderToTexture');
// proxy
this._texContext.setRenderToTexture(target, enableDepthAndStencil, antiAlias > 1);
this.assertLost('setRenderToTexture');
};
ContextWebGL.prototype.setRenderToBackBuffer = function () {
this.stateChangeCallback && this.stateChangeCallback('setRenderToBackBuffer');
this._texContext.setRenderToBackBuffer();
this.assertLost('setRenderToBackBuffer');
};
ContextWebGL.prototype.copyToTexture = function (target, rect, destPoint) {
this.stateChangeCallback && this.stateChangeCallback('setRenderToBackBuffer');
if (!this._texContext._currentRT) {
throw '[ContextWebGL] Try to copy from invalid frambuffer';
}
this._texContext.presentFrameBufferTo(this._texContext._currentRT, target, rect, destPoint);
this.assertLost('copyToTexture');
};
ContextWebGL.prototype.updateBlendStatus = function () {
var bs = this._blendState;
if (!bs.dirty) {
return;
}
var v = bs.values;
var delta = bs.deltaDirty();
// lock last applied state, used for avoid change state over unused, like A (draw) => B => A (draw)
// B state is redundant and should be ignored
bs.lock(true);
if (!v[0] && delta[0]) {
this._gl.disable(this._gl.BLEND);
return;
}
delta[0] && this._gl.enable(this._gl.BLEND);
// always ADD
if (delta[0] || delta[1] || delta[2]) {
if (v[1] !== v[2]) {
this._gl.blendEquationSeparate(v[1], v[2]);
}
else {
this._gl.blendEquation(v[1]);
}
}
// we check that we use separatedBlendMode, for this v[4] (src_alpha) MUST be > -1
// not required check a delta for it
if (delta[0] || delta[3] || delta[4] || v[5] !== -1) {
if (v[5] !== -1) {
this._gl.blendFuncSeparate(v[3], v[4], v[5], v[6]);
}
else {
this._gl.blendFunc(v[3], v[4]);
}
}
};
ContextWebGL.prototype.finish = function () {
this._gl.flush();
this._gl.finish();
this._fenceContext && this._fenceContext.tick();
this.assertLost('finish');
};
ContextWebGL.prototype.translateTriangleFace = function (triangleFace, coordinateSystem) {
switch (triangleFace) {
case ContextGLTriangleFace.BACK:
return (coordinateSystem == CoordinateSystem.LEFT_HANDED) ? this._gl.FRONT : this._gl.BACK;
case ContextGLTriangleFace.FRONT:
return (coordinateSystem == CoordinateSystem.LEFT_HANDED) ? this._gl.BACK : this._gl.FRONT;
case ContextGLTriangleFace.FRONT_AND_BACK:
return this._gl.FRONT_AND_BACK;
default:
throw 'Unknown ContextGLTriangleFace type.'; // TODO error
}
};
return ContextWebGL;
}());
export { ContextWebGL };