UNPKG

@awayjs/stage

Version:
698 lines (697 loc) 32.1 kB
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 };