Skip to content

Revert "Put back in "Merge pull request #489 from adroitwhiz/touching-white-fixes"" #684

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"eslint": "^4.6.1",
"eslint-config-scratch": "^5.0.0",
"gh-pages": "^1.0.0",
"jsdoc": "^3.6.0",
"jsdoc": "^3.5.5",
"json": "^9.0.4",
"playwright-chromium": "^1.0.1",
"scratch-vm": "0.2.0-prerelease.20200622143012",
Expand Down
5 changes: 0 additions & 5 deletions src/Drawable.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ const getLocalPosition = (drawable, vec) => {
// localPosition matches that transformation.
localPosition[0] = 0.5 - (((v0 * m[0]) + (v1 * m[4]) + m[12]) / d);
localPosition[1] = (((v0 * m[1]) + (v1 * m[5]) + m[13]) / d) + 0.5;
// Fix floating point issues near 0.
// TODO: Check if this can be removed after render pull 479 is merged
if (Math.abs(localPosition[0] < 1e-8)) localPosition[0] = 0;
if (Math.abs(localPosition[1] < 1e-8)) localPosition[1] = 0;
// Apply texture effect transform if the localPosition is within the drawable's space,
// and any effects are currently active.
if (drawable.enabledEffects !== 0 &&
Expand Down Expand Up @@ -732,7 +728,6 @@ class Drawable {
dst[3] = 0;
return dst;
}

const textColor =
// commenting out to only use nearest for now
// drawable.useNearest() ?
Expand Down
93 changes: 16 additions & 77 deletions src/RenderWebGL.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,23 +188,9 @@ 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);
Expand Down Expand Up @@ -264,14 +250,7 @@ class RenderWebGL extends EventEmitter {
* @param {number} blue The blue component for the background.
*/
setBackgroundColor (red, green, blue) {
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;

this._backgroundColor = [red, green, blue, 1];
}

/**
Expand Down Expand Up @@ -650,7 +629,7 @@ class RenderWebGL extends EventEmitter {

twgl.bindFramebufferInfo(gl, null);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor.apply(gl, this._backgroundColor4f);
gl.clearColor.apply(gl, this._backgroundColor);
gl.clear(gl.COLOR_BUFFER_BIT);

this._drawThese(this._drawList, ShaderManager.DRAW_MODE.default, this._projection);
Expand Down Expand Up @@ -766,22 +745,12 @@ class RenderWebGL extends EventEmitter {
*/
isTouchingColor (drawableID, color3b, mask3b) {
const candidates = this._candidatesTouching(drawableID, this._visibleDrawList);

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);
// e.g. empty costume, or off the stage
if (bounds === null) return false;
} else if (candidates.length === 0) {
// If not checking for the background color, we can return early if there are no candidate drawables.
if (candidates.length === 0) {
return false;
} else {
bounds = this._candidatesBounds(candidates);
}

const bounds = this._candidatesBounds(candidates);

const maxPixelsForCPU = this._getMaxPixelsForCPU();

const debugCanvasContext = this._debugCanvas && this._debugCanvas.getContext('2d');
Expand Down Expand Up @@ -842,19 +811,6 @@ 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();

Expand All @@ -866,8 +822,15 @@ 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);

// 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);
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);
gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);

let extraUniforms;
Expand All @@ -879,9 +842,6 @@ 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);
Expand All @@ -902,25 +862,12 @@ 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();
}
}

Expand All @@ -939,8 +886,7 @@ class RenderWebGL extends EventEmitter {
}

for (let pixelBase = 0; pixelBase < pixels.length; pixelBase += 4) {
// Transparent pixels are masked (either by the drawable's alpha channel or color mask).
if (pixels[pixelBase + 3] !== 0 && colorMatches(color3b, pixels, pixelBase)) {
if (colorMatches(color3b, pixels, pixelBase)) {
return true;
}
}
Expand Down Expand Up @@ -1375,7 +1321,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._backgroundColor4f);
gl.clearColor.apply(gl, this._backgroundColor);
gl.clear(gl.COLOR_BUFFER_BIT);
this._drawThese(this._drawList, ShaderManager.DRAW_MODE.default, projection);

Expand Down Expand Up @@ -1465,13 +1411,6 @@ 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,
Expand Down
7 changes: 1 addition & 6 deletions src/ShaderManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,7 @@ ShaderManager.DRAW_MODE = {
/**
* Draw a line with caps.
*/
line: 'line',

/**
* Draw the background in a certain color. Must sometimes be used instead of gl.clear.
*/
background: 'background'
line: 'line'
};

module.exports = ShaderManager;
30 changes: 10 additions & 20 deletions src/Silhouette.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@
*/
let __SilhouetteUpdateCanvas;

// Optimized Math.min and Math.max for integers;
// taken from https://web.archive.org/web/20190716181049/http://guihaire.com/code/?p=549
const intMin = (i, j) => j ^ ((i ^ j) & ((i - j) >> 31));
const intMax = (i, j) => i ^ ((i ^ j) & ((i - j) >> 31));

/**
* Internal helper function (in hopes that compiler can inline). Get a pixel
* from silhouette data, or 0 if outside it's bounds.
Expand Down Expand Up @@ -45,18 +40,13 @@ const __cornerWork = [
/**
* Get the color from a given silhouette at an x/y local texture position.
* Multiply color values by alpha for proper blending.
* @param {Silhouette} $0 The silhouette to sample.
* @param {number} x X position of texture [0, width).
* @param {number} y Y position of texture [0, height).
* @param {Silhouette} The silhouette to sample.
* @param {number} x X position of texture (0-1).
* @param {number} y Y position of texture (0-1).
* @param {Uint8ClampedArray} dst A color 4b space.
* @return {Uint8ClampedArray} The dst vector.
*/
const getColor4b = ({_width: width, _height: height, _colorData: data}, x, y, dst) => {
// Clamp coords to edge, matching GL_CLAMP_TO_EDGE.
// (See github.com/LLK/scratch-render/blob/954cfff02b08069a082cbedd415c1fecd9b1e4fb/src/BitmapSkin.js#L88)
x = intMax(0, intMin(x, width - 1));
y = intMax(0, intMin(y, height - 1));

// 0 if outside bounds, otherwise read from data.
if (x >= width || y >= height || x < 0 || y < 0) {
return dst.fill(0);
Expand All @@ -74,17 +64,17 @@ const getColor4b = ({_width: width, _height: height, _colorData: data}, x, y, ds
/**
* Get the color from a given silhouette at an x/y local texture position.
* Do not multiply color values by alpha, as it has already been done.
* @param {Silhouette} $0 The silhouette to sample.
* @param {number} x X position of texture [0, width).
* @param {number} y Y position of texture [0, height).
* @param {Silhouette} The silhouette to sample.
* @param {number} x X position of texture (0-1).
* @param {number} y Y position of texture (0-1).
* @param {Uint8ClampedArray} dst A color 4b space.
* @return {Uint8ClampedArray} The dst vector.
*/
const getPremultipliedColor4b = ({_width: width, _height: height, _colorData: data}, x, y, dst) => {
// Clamp coords to edge, matching GL_CLAMP_TO_EDGE.
x = intMax(0, intMin(x, width - 1));
y = intMax(0, intMin(y, height - 1));

// 0 if outside bounds, otherwise read from data.
if (x >= width || y >= height || x < 0 || y < 0) {
return dst.fill(0);
}
const offset = ((y * width) + x) * 4;
dst[0] = data[offset];
dst[1] = data[offset + 1];
Expand Down
16 changes: 2 additions & 14 deletions src/shaders/sprite.frag
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,9 @@ 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.
Expand Down Expand Up @@ -115,7 +109,7 @@ const vec2 kCenter = vec2(0.5, 0.5);

void main()
{
#if !(defined(DRAW_MODE_line) || defined(DRAW_MODE_background))
#ifndef DRAW_MODE_line
vec2 texcoord0 = v_texCoord;

#ifdef ENABLE_mosaic
Expand Down Expand Up @@ -221,9 +215,7 @@ void main()
gl_FragColor.rgb /= gl_FragColor.a + epsilon;
#endif

#endif // !(defined(DRAW_MODE_line) || defined(DRAW_MODE_background))

#ifdef DRAW_MODE_line
#else // DRAW_MODE_line
// Maaaaagic antialiased-line-with-round-caps shader.

// "along-the-lineness". This increases parallel to the line.
Expand All @@ -242,8 +234,4 @@ 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
}
4 changes: 1 addition & 3 deletions src/shaders/sprite.vert
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ uniform vec4 u_penPoints;
const float epsilon = 1e-3;
#endif

#if !(defined(DRAW_MODE_line) || defined(DRAW_MODE_background))
#ifndef DRAW_MODE_line
uniform mat4 u_projectionMatrix;
uniform mat4 u_modelMatrix;
attribute vec2 a_texCoord;
Expand Down Expand Up @@ -66,8 +66,6 @@ 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;
Expand Down
Binary file removed test/integration/scratch-tests/clear-color.sb3
Binary file not shown.