Merge pull request #410 from LLK/revert-407-coordinates-fixups

Revert "Adjust CPU isTouchingColor to match GPU results"
This commit is contained in:
Chris Willis-Ford 2019-02-07 13:11:57 -08:00 committed by GitHub
commit c7b22b58c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 62 deletions

View File

@ -24,11 +24,12 @@ const __isTouchingPosition = twgl.v3.create();
* @return {twgl.v3} [x,y] texture space float vector - transformed by effects and matrix
*/
const getLocalPosition = (drawable, vec) => {
// Transform from world coordinates to Drawable coordinates.
// Transfrom from world coordinates to Drawable coordinates.
const localPosition = __isTouchingPosition;
const v0 = vec[0];
const v1 = vec[1];
const m = drawable._inverseMatrix;
// var v2 = v[2];
const d = (v0 * m[3]) + (v1 * m[7]) + m[15];
// The RenderWebGL quad flips the texture's X axis. So rendered bottom
// left is 1, 0 and the top right is 0, 1. Flip the X axis so
@ -341,7 +342,7 @@ class Drawable {
// Drawable configures a 3D matrix for drawing in WebGL, but most values
// will never be set because the inputs are on the X and Y position axis
// and the Z rotation axis. Drawable can bring the work inside
// _calculateTransform and greatly reduce the amount of math and array
// _calculateTransform and greatly reduce the ammount of math and array
// assignments needed.
const scale0 = this._skinScale[0];
@ -624,6 +625,11 @@ class Drawable {
*/
static sampleColor4b (vec, drawable, dst) {
const localPosition = getLocalPosition(drawable, vec);
if (localPosition[0] < 0 || localPosition[1] < 0 ||
localPosition[0] > 1 || localPosition[1] > 1) {
dst[3] = 0;
return dst;
}
const textColor =
// commenting out to only use nearest for now
// drawable.useNearest ?

View File

@ -256,7 +256,8 @@ class RenderWebGL extends EventEmitter {
this._yBottom = yBottom;
this._yTop = yTop;
this._projection = this._makeOrthoProjection(xLeft, xRight, yBottom, yTop);
// swap yBottom & yTop to fit Scratch convention of +y=up
this._projection = twgl.m4.ortho(xLeft, xRight, yBottom, yTop, -1, 1);
this._setNativeSize(Math.abs(xRight - xLeft), Math.abs(yBottom - yTop));
}
@ -280,20 +281,6 @@ class RenderWebGL extends EventEmitter {
this.emit(RenderConstants.Events.NativeSizeChanged, {newSize: this._nativeSize});
}
/**
* Build a projection matrix for Scratch coordinates. For example, `_makeOrthoProjection(-240,240,-180,180)` will
* mean the lower-left pixel is at (-240,-179) and the upper right pixel is at (239,180), matching Scratch 2.0.
* @param {number} xLeft - the left edge of the projection volume (-240)
* @param {number} xRight - the right edge of the projection volume (240)
* @param {number} yBottom - the bottom edge of the projection volume (-180)
* @param {number} yTop - the top edge of the projection volume (180)
* @returns {module:twgl/m4.Mat4} - a projection matrix containing [xLeft,xRight) and (yBottom,yTop]
*/
_makeOrthoProjection (xLeft, xRight, yBottom, yTop) {
// swap yBottom & yTop to fit Scratch convention of +y=up
return twgl.m4.ortho(xLeft, xRight, yBottom, yTop, -1, 1);
}
/**
* Create a new bitmap skin from a snapshot of the provided bitmap data.
* @param {ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} bitmapData - new contents for this skin.
@ -531,7 +518,7 @@ class RenderWebGL extends EventEmitter {
* Returns the position of the given drawableID in the draw list. This is
* the absolute position irrespective of layer group.
* @param {number} drawableID The drawable ID to find.
* @return {number} The position of the given drawable ID.
* @return {number} The postion of the given drawable ID.
*/
getDrawableOrder (drawableID) {
return this._drawList.indexOf(drawableID);
@ -545,7 +532,7 @@ class RenderWebGL extends EventEmitter {
* "go to back": setDrawableOrder(id, 1); (assuming stage at 0).
* "go to front": setDrawableOrder(id, Infinity);
* @param {int} drawableID ID of Drawable to reorder.
* @param {number} order New absolute order or relative order adjustment.
* @param {number} order New absolute order or relative order adjusment.
* @param {string=} group Name of layer group drawable belongs to.
* Reordering will not take place if drawable cannot be found within the bounds
* of the layer group.
@ -716,7 +703,7 @@ class RenderWebGL extends EventEmitter {
/**
* Check if a particular Drawable is touching a particular color.
* Unlike touching drawable, if the "tester" is invisible, we will still test.
* Unlike touching drawable, if the "tester" is invisble, we will still test.
* @param {int} drawableID The ID of the Drawable to check.
* @param {Array<int>} color3b Test if the Drawable is touching this color.
* @param {Array<int>} [mask3b] Optionally mask the check to this part of Drawable.
@ -741,23 +728,23 @@ class RenderWebGL extends EventEmitter {
const color = __touchingColor;
const hasMask = Boolean(mask3b);
// Scratch Space - +y is top
for (let y = 0; y < bounds.height; ++y) {
if (bounds.width * y * (candidates.length + 1) >= __cpuTouchingColorPixelCount) {
return this._isTouchingColorGpuFin(bounds, color3b, y);
for (let y = bounds.bottom; y <= bounds.top; y++) {
if (bounds.width * (y - bounds.bottom) * (candidates.length + 1) >= __cpuTouchingColorPixelCount) {
return this._isTouchingColorGpuFin(bounds, color3b, y - bounds.bottom);
}
for (let x = 0; x < bounds.width; ++x) {
point[0] = bounds.left + x; // bounds.left <= point[0] < bounds.right
point[1] = bounds.top - y; // bounds.bottom < point[1] <= bounds.top ("flipped")
// if we use a mask, check our sample color...
if (hasMask ?
maskMatches(Drawable.sampleColor4b(point, drawable, color), mask3b) :
drawable.isTouching(point)) {
RenderWebGL.sampleColor3b(point, candidates, color);
// ...and the target color is drawn at this pixel
if (colorMatches(color, color3b, 0)) {
return true;
}
// Scratch Space - +y is top
for (let x = bounds.left; x <= bounds.right; x++) {
point[1] = y;
point[0] = x;
if (
// if we use a mask, check our sample color
(hasMask ?
maskMatches(Drawable.sampleColor4b(point, drawable, color), mask3b) :
drawable.isTouching(point)) &&
// and the target color is drawn at this pixel
colorMatches(RenderWebGL.sampleColor3b(point, candidates, color), color3b, 0)
) {
return true;
}
}
}
@ -773,7 +760,7 @@ class RenderWebGL extends EventEmitter {
// Limit size of viewport to the bounds around the target Drawable,
// and create the projection matrix for the draw.
gl.viewport(0, 0, bounds.width, bounds.height);
const projection = this._makeOrthoProjection(bounds.left, bounds.right, bounds.top, bounds.bottom);
const projection = twgl.m4.ortho(bounds.left, bounds.right, bounds.top, bounds.bottom, -1, 1);
let fillBackgroundColor = this._backgroundColor;
@ -856,7 +843,7 @@ class RenderWebGL extends EventEmitter {
const candidates = this._candidatesTouching(drawableID,
// even if passed an invisible drawable, we will NEVER touch it!
candidateIDs.filter(id => this._allDrawables[id]._visible));
// if we are invisible we don't touch anything.
// if we are invisble we don't touch anything.
if (candidates.length === 0 || !this._allDrawables[drawableID]._visible) {
return false;
}
@ -889,7 +876,7 @@ class RenderWebGL extends EventEmitter {
/**
* Convert a client based x/y position on the canvas to a Scratch 3 world space
* Rectangle. This creates rectangles with a radius to cover selecting multiple
* Rectangle. This creates recangles with a radius to cover selecting multiple
* scratch pixels with touch / small render areas.
*
* @param {int} centerX The client x coordinate of the picking location.
@ -1006,7 +993,7 @@ class RenderWebGL extends EventEmitter {
for (worldPos[0] = bounds.left; worldPos[0] <= bounds.right; worldPos[0]++) {
// Check candidates in the reverse order they would have been
// drawn. This will determine what candidate's silhouette pixel
// drawn. This will determine what candiate's silhouette pixel
// would have been drawn at the point.
for (let d = candidateIDs.length - 1; d >= 0; d--) {
const id = candidateIDs[d];
@ -1090,7 +1077,7 @@ class RenderWebGL extends EventEmitter {
// Limit size of viewport to the bounds around the target Drawable,
// and create the projection matrix for the draw.
gl.viewport(0, 0, bounds.width, bounds.height);
const projection = this._makeOrthoProjection(bounds.left, bounds.right, bounds.top, bounds.bottom);
const projection = twgl.m4.ortho(bounds.left, bounds.right, bounds.top, bounds.bottom, -1, 1);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
@ -1165,7 +1152,7 @@ class RenderWebGL extends EventEmitter {
const pickY = bounds.top - scratchY;
gl.viewport(0, 0, bounds.width, bounds.height);
const projection = this._makeOrthoProjection(bounds.left, bounds.right, bounds.top, bounds.bottom);
const projection = twgl.m4.ortho(bounds.left, bounds.right, bounds.top, bounds.bottom, -1, 1);
gl.clearColor.apply(gl, this._backgroundColor);
gl.clear(gl.COLOR_BUFFER_BIT);
@ -1408,7 +1395,7 @@ class RenderWebGL extends EventEmitter {
// Limit size of viewport to the bounds around the stamp Drawable and create the projection matrix for the draw.
gl.viewport(0, 0, bounds.width, bounds.height);
const projection = this._makeOrthoProjection(bounds.left, bounds.right, bounds.top, bounds.bottom);
const projection = twgl.m4.ortho(bounds.left, bounds.right, bounds.top, bounds.bottom, -1, 1);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
@ -1497,7 +1484,7 @@ class RenderWebGL extends EventEmitter {
* can skip superfluous extra state calls when it is already in that
* region. Since one region may be entered from within another a exit
* handle can also be registered that is called when a new region is about
* to be entered to restore a common in-between state.
* to be entered to restore a common inbetween state.
*
* @param {any} regionId - id of the region to enter
* @param {function} enter - handle to call when first entering a region
@ -1629,7 +1616,7 @@ class RenderWebGL extends EventEmitter {
*
* The determinant is useful in this case to know if AC is counter
* clockwise from AB. A positive value means the AC is counter
* clockwise from AC. A negative value means AC is clockwise from AB.
* clockwise from AC. A negative value menas AC is clockwise from AB.
*
* @param {Float32Array} A A 2d vector in space.
* @param {Float32Array} B A 2d vector in space.

View File

@ -11,16 +11,16 @@
let __SilhouetteUpdateCanvas;
/**
* Internal helper function (in hopes that compiler can inline). Get the alpha value for a texel in the silhouette
* data, or 0 if outside it's bounds.
* Internal helper function (in hopes that compiler can inline). Get a pixel
* from silhouette data, or 0 if outside it's bounds.
* @private
* @param {Silhouette} $0 - has data, width, and height
* @param {number} x - X position in texels (0..width).
* @param {number} y - Y position in texels (0..height).
* @param {Silhouette} silhouette - has data width and height
* @param {number} x - x
* @param {number} y - y
* @return {number} Alpha value for x/y position
*/
const getPoint = ({_width: width, _height: height, _data: data}, x, y) => {
// 0 if outside bounds, otherwise read from data.
// 0 if outside bouds, otherwise read from data.
if (x >= width || y >= height || x < 0 || y < 0) {
return 0;
}
@ -39,14 +39,14 @@ const __cornerWork = [
/**
* Get the color from a given silhouette at an x/y local texture position.
* @param {Silhouette} $0 - The silhouette to sample.
* @param {number} x - X position in texels (0..width).
* @param {number} y - Y position in texels (0..height).
* @param {Uint8ClampedArray} dst - A color 4b space.
* @return {Uint8ClampedArray} - The dst vector.
* @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) => {
// 0 if outside bounds, otherwise read from data.
// 0 if outside bouds, otherwise read from data.
if (x >= width || y >= height || x < 0 || y < 0) {
return dst.fill(0);
}
@ -102,7 +102,7 @@ class Silhouette {
this._data = new Uint8ClampedArray(imageData.data.length / 4);
this._colorData = imageData.data;
// delete our custom overridden "uninitialized" color functions
// delete our custom overriden "uninitalized" color functions
// let the prototype work for itself
delete this.colorAtNearest;
delete this.colorAtLinear;
@ -120,10 +120,12 @@ class Silhouette {
* @returns {Uint8ClampedArray} dst
*/
colorAtNearest (vec, dst) {
const x = Math.round(vec[0] * this._width);
const y = Math.round(vec[1] * this._height);
const color = getColor4b(this, x, y, dst);
return color;
return getColor4b(
this,
Math.floor(vec[0] * (this._width - 1)),
Math.floor(vec[1] * (this._height - 1)),
dst
);
}
/**