|
|
|
|
@@ -182,9 +182,23 @@ class RenderWebGL extends EventEmitter {
|
|
|
|
|
/** @type {function} */
|
|
|
|
|
this._exitRegion = null;
|
|
|
|
|
|
|
|
|
|
/** @type {object} */
|
|
|
|
|
this._backgroundDrawRegionId = {
|
|
|
|
|
enter: () => this._enterDrawBackground(),
|
|
|
|
|
exit: () => this._exitDrawBackground()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** @type {Array.<snapshotCallback>} */
|
|
|
|
|
this._snapshotCallbacks = [];
|
|
|
|
|
|
|
|
|
|
/** @type {Array<number>}
|
|
|
|
|
* @readonly */
|
|
|
|
|
this._backgroundColor4f = [0, 0, 0, 0];
|
|
|
|
|
|
|
|
|
|
/** @type {Uint8ClampedArray}
|
|
|
|
|
* @readonly */
|
|
|
|
|
this._backgroundColor3b = new Uint8ClampedArray(3);
|
|
|
|
|
|
|
|
|
|
this._createGeometry();
|
|
|
|
|
|
|
|
|
|
this.on(RenderConstants.Events.NativeSizeChanged, this.onNativeSizeChanged);
|
|
|
|
|
@@ -244,7 +258,12 @@ class RenderWebGL extends EventEmitter {
|
|
|
|
|
* @param {number} blue The blue component for the background.
|
|
|
|
|
*/
|
|
|
|
|
setBackgroundColor (red, green, blue) {
|
|
|
|
|
this._backgroundColor = [red, green, blue, 1];
|
|
|
|
|
this._backgroundColor4f = [red, green, blue, 1];
|
|
|
|
|
|
|
|
|
|
this._backgroundColor3b[0] = red * 255;
|
|
|
|
|
this._backgroundColor3b[1] = green * 255;
|
|
|
|
|
this._backgroundColor3b[2] = blue * 255;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -623,7 +642,7 @@ class RenderWebGL extends EventEmitter {
|
|
|
|
|
|
|
|
|
|
twgl.bindFramebufferInfo(gl, null);
|
|
|
|
|
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
|
|
|
|
|
gl.clearColor.apply(gl, this._backgroundColor);
|
|
|
|
|
gl.clearColor.apply(gl, this._backgroundColor4f);
|
|
|
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
|
|
|
|
|
|
|
|
this._drawThese(this._drawList, ShaderManager.DRAW_MODE.default, this._projection);
|
|
|
|
|
@@ -739,11 +758,19 @@ class RenderWebGL extends EventEmitter {
|
|
|
|
|
*/
|
|
|
|
|
isTouchingColor (drawableID, color3b, mask3b) {
|
|
|
|
|
const candidates = this._candidatesTouching(drawableID, this._visibleDrawList);
|
|
|
|
|
if (candidates.length === 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bounds = this._candidatesBounds(candidates);
|
|
|
|
|
let bounds;
|
|
|
|
|
if (colorMatches(color3b, this._backgroundColor3b, 0)) {
|
|
|
|
|
// If the color we're checking for is the background color, don't confine the check to
|
|
|
|
|
// candidate drawables' bounds--since the background spans the entire stage, we must check
|
|
|
|
|
// everything that lies inside the drawable.
|
|
|
|
|
bounds = this._touchingBounds(drawableID);
|
|
|
|
|
} else if (candidates.length === 0) {
|
|
|
|
|
// If not checking for the background color, we can return early if there are no candidate drawables.
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
bounds = this._candidatesBounds(candidates);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const maxPixelsForCPU = this._getMaxPixelsForCPU();
|
|
|
|
|
|
|
|
|
|
@@ -805,6 +832,19 @@ class RenderWebGL extends EventEmitter {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_enterDrawBackground () {
|
|
|
|
|
const gl = this.gl;
|
|
|
|
|
const currentShader = this._shaderManager.getShader(ShaderManager.DRAW_MODE.background, 0);
|
|
|
|
|
gl.disable(gl.BLEND);
|
|
|
|
|
gl.useProgram(currentShader.program);
|
|
|
|
|
twgl.setBuffersAndAttributes(gl, currentShader, this._bufferInfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_exitDrawBackground () {
|
|
|
|
|
const gl = this.gl;
|
|
|
|
|
gl.enable(gl.BLEND);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_isTouchingColorGpuStart (drawableID, candidateIDs, bounds, color3b, mask3b) {
|
|
|
|
|
this._doExitDrawRegion();
|
|
|
|
|
|
|
|
|
|
@@ -816,15 +856,8 @@ class RenderWebGL extends EventEmitter {
|
|
|
|
|
gl.viewport(0, 0, bounds.width, bounds.height);
|
|
|
|
|
const projection = twgl.m4.ortho(bounds.left, bounds.right, bounds.top, bounds.bottom, -1, 1);
|
|
|
|
|
|
|
|
|
|
let fillBackgroundColor = this._backgroundColor;
|
|
|
|
|
|
|
|
|
|
// When using masking such that the background fill color will showing through, ensure we don't
|
|
|
|
|
// fill using the same color that we are trying to detect!
|
|
|
|
|
if (color3b[0] > 196 && color3b[1] > 196 && color3b[2] > 196) {
|
|
|
|
|
fillBackgroundColor = [0, 0, 0, 255];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gl.clearColor.apply(gl, fillBackgroundColor);
|
|
|
|
|
// Clear the query buffer to fully transparent. This will be the color of pixels that fail the stencil test.
|
|
|
|
|
gl.clearColor(0, 0, 0, 0);
|
|
|
|
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
|
|
|
|
|
|
|
|
|
|
let extraUniforms;
|
|
|
|
|
@@ -836,6 +869,9 @@ class RenderWebGL extends EventEmitter {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Using the stencil buffer, mask out the drawing to either the drawable's bounds
|
|
|
|
|
// or pixels of the drawable which match the mask color, depending on whether a mask color is given.
|
|
|
|
|
// Masked-out pixels will not be checked.
|
|
|
|
|
gl.enable(gl.STENCIL_TEST);
|
|
|
|
|
gl.stencilFunc(gl.ALWAYS, 1, 1);
|
|
|
|
|
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
|
|
|
|
|
@@ -856,12 +892,25 @@ class RenderWebGL extends EventEmitter {
|
|
|
|
|
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
|
|
|
|
|
gl.colorMask(true, true, true, true);
|
|
|
|
|
|
|
|
|
|
// Draw the background as a quad. Drawing a background with gl.clear will not mask to the stenciled area.
|
|
|
|
|
this.enterDrawRegion(this._backgroundDrawRegionId);
|
|
|
|
|
|
|
|
|
|
const uniforms = {
|
|
|
|
|
u_backgroundColor: this._backgroundColor4f
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const currentShader = this._shaderManager.getShader(ShaderManager.DRAW_MODE.background, 0);
|
|
|
|
|
twgl.setUniforms(currentShader, uniforms);
|
|
|
|
|
twgl.drawBufferInfo(gl, this._bufferInfo, gl.TRIANGLES);
|
|
|
|
|
|
|
|
|
|
// Draw the candidate drawables on top of the background.
|
|
|
|
|
this._drawThese(candidateIDs, ShaderManager.DRAW_MODE.default, projection,
|
|
|
|
|
{idFilterFunc: testID => testID !== drawableID}
|
|
|
|
|
);
|
|
|
|
|
} finally {
|
|
|
|
|
gl.colorMask(true, true, true, true);
|
|
|
|
|
gl.disable(gl.STENCIL_TEST);
|
|
|
|
|
this._doExitDrawRegion();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -880,7 +929,8 @@ class RenderWebGL extends EventEmitter {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (let pixelBase = 0; pixelBase < pixels.length; pixelBase += 4) {
|
|
|
|
|
if (colorMatches(color3b, pixels, pixelBase)) {
|
|
|
|
|
// Transparent pixels are masked (either by the drawable's bounds or color mask).
|
|
|
|
|
if (pixels[pixelBase + 3] !== 0 && colorMatches(color3b, pixels, pixelBase)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -1204,7 +1254,7 @@ class RenderWebGL extends EventEmitter {
|
|
|
|
|
gl.viewport(0, 0, bounds.width, bounds.height);
|
|
|
|
|
const projection = twgl.m4.ortho(bounds.left, bounds.right, bounds.top, bounds.bottom, -1, 1);
|
|
|
|
|
|
|
|
|
|
gl.clearColor.apply(gl, this._backgroundColor);
|
|
|
|
|
gl.clearColor.apply(gl, this._backgroundColor4f);
|
|
|
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
|
|
|
this._drawThese(this._drawList, ShaderManager.DRAW_MODE.default, projection);
|
|
|
|
|
|
|
|
|
|
|