mirror of
https://github.com/scratchfoundation/scratch-render.git
synced 2025-07-25 13:38:50 -04:00
Revert "Revert "Revert "Revert "Merge pull request #489 from adroitwhiz/touching-white-fixes""""
This commit is contained in:
parent
954cfff02b
commit
90040dfa55
5 changed files with 99 additions and 21 deletions
src
test/integration/scratch-tests
|
@ -188,9 +188,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>} */
|
||||
// Don't set this directly-- use setBackgroundColor so it stays in sync with _backgroundColor3b
|
||||
this._backgroundColor4f = [0, 0, 0, 1];
|
||||
|
||||
/** @type {Uint8ClampedArray} */
|
||||
// Don't set this directly-- use setBackgroundColor so it stays in sync with _backgroundColor4f
|
||||
this._backgroundColor3b = new Uint8ClampedArray(3);
|
||||
|
||||
this._createGeometry();
|
||||
|
||||
this.on(RenderConstants.Events.NativeSizeChanged, this.onNativeSizeChanged);
|
||||
|
@ -250,7 +264,14 @@ 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[0] = red;
|
||||
this._backgroundColor4f[1] = green;
|
||||
this._backgroundColor4f[2] = blue;
|
||||
|
||||
this._backgroundColor3b[0] = red * 255;
|
||||
this._backgroundColor3b[1] = green * 255;
|
||||
this._backgroundColor3b[2] = blue * 255;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -629,7 +650,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);
|
||||
|
@ -745,11 +766,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();
|
||||
|
||||
|
@ -811,6 +840,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();
|
||||
|
||||
|
@ -822,15 +864,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;
|
||||
|
@ -842,6 +877,9 @@ class RenderWebGL extends EventEmitter {
|
|||
}
|
||||
|
||||
try {
|
||||
// Using the stencil buffer, mask out the drawing to either the drawable's alpha channel
|
||||
// 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);
|
||||
|
@ -862,12 +900,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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -886,7 +937,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 alpha channel or color mask).
|
||||
if (pixels[pixelBase + 3] !== 0 && colorMatches(color3b, pixels, pixelBase)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1321,7 +1373,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);
|
||||
|
||||
|
@ -1409,6 +1461,13 @@ class RenderWebGL extends EventEmitter {
|
|||
// Update the CPU position data
|
||||
drawable.updateCPURenderAttributes();
|
||||
const candidateBounds = drawable.getFastBounds();
|
||||
|
||||
// Push bounds out to integers. If a drawable extends out into half a pixel, that half-pixel still
|
||||
// needs to be tested. Plus, in some areas we construct another rectangle from the union of these,
|
||||
// and iterate over its pixels (width * height). Turns out that doesn't work so well when the
|
||||
// width/height aren't integers.
|
||||
candidateBounds.snapToInt();
|
||||
|
||||
if (bounds.intersects(candidateBounds)) {
|
||||
result.push({
|
||||
id,
|
||||
|
|
|
@ -176,7 +176,12 @@ ShaderManager.DRAW_MODE = {
|
|||
/**
|
||||
* Draw a line with caps.
|
||||
*/
|
||||
line: 'line'
|
||||
line: 'line',
|
||||
|
||||
/**
|
||||
* Draw the background in a certain color. Must sometimes be used instead of gl.clear.
|
||||
*/
|
||||
background: 'background'
|
||||
};
|
||||
|
||||
module.exports = ShaderManager;
|
||||
|
|
|
@ -39,9 +39,15 @@ uniform float u_lineThickness;
|
|||
uniform float u_lineLength;
|
||||
#endif // DRAW_MODE_line
|
||||
|
||||
#ifdef DRAW_MODE_background
|
||||
uniform vec4 u_backgroundColor;
|
||||
#endif // DRAW_MODE_background
|
||||
|
||||
uniform sampler2D u_skin;
|
||||
|
||||
#ifndef DRAW_MODE_background
|
||||
varying vec2 v_texCoord;
|
||||
#endif
|
||||
|
||||
// Add this to divisors to prevent division by 0, which results in NaNs propagating through calculations.
|
||||
// Smaller values can cause problems on some mobile devices.
|
||||
|
@ -109,7 +115,7 @@ const vec2 kCenter = vec2(0.5, 0.5);
|
|||
|
||||
void main()
|
||||
{
|
||||
#ifndef DRAW_MODE_line
|
||||
#if !(defined(DRAW_MODE_line) || defined(DRAW_MODE_background))
|
||||
vec2 texcoord0 = v_texCoord;
|
||||
|
||||
#ifdef ENABLE_mosaic
|
||||
|
@ -215,7 +221,9 @@ void main()
|
|||
gl_FragColor.rgb /= gl_FragColor.a + epsilon;
|
||||
#endif
|
||||
|
||||
#else // DRAW_MODE_line
|
||||
#endif // !(defined(DRAW_MODE_line) || defined(DRAW_MODE_background))
|
||||
|
||||
#ifdef DRAW_MODE_line
|
||||
// Maaaaagic antialiased-line-with-round-caps shader.
|
||||
|
||||
// "along-the-lineness". This increases parallel to the line.
|
||||
|
@ -234,4 +242,8 @@ void main()
|
|||
// the closer we are to the line, invert it.
|
||||
gl_FragColor = u_lineColor * clamp(1.0 - line, 0.0, 1.0);
|
||||
#endif // DRAW_MODE_line
|
||||
|
||||
#ifdef DRAW_MODE_background
|
||||
gl_FragColor = u_backgroundColor;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ uniform vec4 u_penPoints;
|
|||
const float epsilon = 1e-3;
|
||||
#endif
|
||||
|
||||
#ifndef DRAW_MODE_line
|
||||
#if !(defined(DRAW_MODE_line) || defined(DRAW_MODE_background))
|
||||
uniform mat4 u_projectionMatrix;
|
||||
uniform mat4 u_modelMatrix;
|
||||
attribute vec2 a_texCoord;
|
||||
|
@ -66,6 +66,8 @@ void main() {
|
|||
// 4. Apply view transform
|
||||
position *= 2.0 / u_stageSize;
|
||||
gl_Position = vec4(position, 0, 1);
|
||||
#elif defined(DRAW_MODE_background)
|
||||
gl_Position = vec4(a_position * 2.0, 0, 1);
|
||||
#else
|
||||
gl_Position = u_projectionMatrix * u_modelMatrix * vec4(a_position, 0, 1);
|
||||
v_texCoord = a_texCoord;
|
||||
|
|
BIN
test/integration/scratch-tests/clear-color.sb3
Normal file
BIN
test/integration/scratch-tests/clear-color.sb3
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue