Compare commits

..

1 Commits

Author SHA1 Message Date
greenkeeper[bot]
12db761db3 chore(package): update babel-loader to version 8.0.0 2018-08-28 21:20:43 +00:00
7 changed files with 83 additions and 157 deletions

View File

@@ -26,7 +26,7 @@
"devDependencies": {
"babel-core": "^6.23.1",
"babel-eslint": "^8.2.1",
"babel-loader": "^7.1.4",
"babel-loader": "^8.0.0",
"babel-polyfill": "^6.22.0",
"babel-preset-env": "^1.6.1",
"chromeless": "^1.5.1",
@@ -37,12 +37,12 @@
"gh-pages": "^1.0.0",
"jsdoc": "^3.5.5",
"json": "^9.0.4",
"scratch-vm": "0.2.0-prerelease.20181024204838",
"scratch-vm": "0.2.0-prerelease.20180824135031",
"tap": "^11.0.0",
"travis-after-all": "^1.4.4",
"uglifyjs-webpack-plugin": "^1.2.5",
"webpack": "^4.8.0",
"webpack-cli": "^3.1.0",
"webpack-cli": "^2.0.15",
"webpack-dev-server": "^3.1.4"
},
"dependencies": {
@@ -53,7 +53,7 @@
"minilog": "3.1.0",
"raw-loader": "^0.5.1",
"scratch-storage": "^1.0.0",
"scratch-svg-renderer": "0.2.0-prerelease.20181220183040",
"scratch-svg-renderer": "0.2.0-prerelease.20180817005452",
"twgl.js": "4.4.0"
}
}

View File

@@ -190,8 +190,8 @@ class Drawable {
if ('position' in properties && (
this._position[0] !== properties.position[0] ||
this._position[1] !== properties.position[1])) {
this._position[0] = Math.round(properties.position[0]);
this._position[1] = Math.round(properties.position[1]);
this._position[0] = properties.position[0];
this._position[1] = properties.position[1];
dirty = true;
}
if ('direction' in properties && this._direction !== properties.direction) {
@@ -426,16 +426,16 @@ class Drawable {
* Should the drawable use NEAREST NEIGHBOR or LINEAR INTERPOLATION mode
*/
get useNearest () {
// Raster skins (bitmaps) should always prefer nearest neighbor
if (this.skin.isRaster) {
return true;
}
// We can't use nearest neighbor unless we are a multiple of 90 rotation
if (this._direction % 90 !== 0) {
return false;
}
// Raster skins (bitmaps) should always prefer nearest neighbor
if (this.skin.isRaster) {
return true;
}
// If the scale of the skin is very close to 100 (0.99999 variance is okay I guess)
if (Math.abs(this.scale[0]) > 99 && Math.abs(this.scale[0]) < 101 &&
Math.abs(this.scale[1]) > 99 && Math.abs(this.scale[1]) < 101) {
@@ -536,15 +536,13 @@ class Drawable {
_getTransformedHullPoints () {
const projection = twgl.m4.ortho(-1, 1, -1, 1, -1, 1);
const skinSize = this.skin.size;
const halfXPixel = 1 / skinSize[0] / 2;
const halfYPixel = 1 / skinSize[1] / 2;
const tm = twgl.m4.multiply(this._uniforms.u_modelMatrix, projection);
const transformedHullPoints = [];
for (let i = 0; i < this._convexHullPoints.length; i++) {
const point = this._convexHullPoints[i];
const glPoint = twgl.v3.create(
0.5 + (-point[0] / skinSize[0]) - halfXPixel,
(point[1] / skinSize[1]) - 0.5 + halfYPixel,
0.5 + (-point[0] / skinSize[0]),
(point[1] / skinSize[1]) - 0.5,
0
);
twgl.m4.transformPoint(tm, glPoint, glPoint);

View File

@@ -178,9 +178,6 @@ class RenderWebGL extends EventEmitter {
/** @type {function} */
this._exitRegion = null;
/** @type {Array.<snapshotCallback>} */
this._snapshotCallbacks = [];
this._svgTextBubble = new SVGTextBubble();
this._createGeometry();
@@ -204,13 +201,6 @@ class RenderWebGL extends EventEmitter {
return this._gl;
}
/**
* @returns {HTMLCanvasElement} the canvas of the WebGL rendering context associated with this renderer.
*/
get canvas () {
return this._gl && this._gl.canvas;
}
/**
* Set the physical size of the stage in device-independent pixels.
* This will be multiplied by the device's pixel ratio on high-DPI displays.
@@ -599,11 +589,6 @@ class RenderWebGL extends EventEmitter {
gl.clear(gl.COLOR_BUFFER_BIT);
this._drawThese(this._drawList, ShaderManager.DRAW_MODE.default, this._projection);
if (this._snapshotCallbacks.length > 0) {
const snapshot = gl.canvas.toDataURL();
this._snapshotCallbacks.forEach(cb => cb(snapshot));
this._snapshotCallbacks = [];
}
}
/**
@@ -930,13 +915,6 @@ class RenderWebGL extends EventEmitter {
const bounds = this.clientSpaceToScratchBounds(centerX, centerY, touchWidth, touchHeight);
const worldPos = twgl.v3.create();
drawable.updateMatrix();
if (drawable.skin) {
drawable.skin.updateSilhouette();
} else {
log.warn(`Could not find skin for drawable with id: ${drawableID}`);
}
for (worldPos[1] = bounds.bottom; worldPos[1] <= bounds.top; worldPos[1]++) {
for (worldPos[0] = bounds.left; worldPos[0] <= bounds.right; worldPos[0]++) {
if (drawable.isTouching(worldPos)) {
@@ -967,11 +945,7 @@ class RenderWebGL extends EventEmitter {
// default pick list ignores visible and ghosted sprites.
if (drawable.getVisible() && drawable.getUniforms().u_ghost !== 0) {
drawable.updateMatrix();
if (drawable.skin) {
drawable.skin.updateSilhouette();
} else {
log.warn(`Could not find skin for drawable with id: ${id}`);
}
drawable.skin.updateSilhouette();
return true;
}
return false;
@@ -979,12 +953,7 @@ class RenderWebGL extends EventEmitter {
if (candidateIDs.length === 0) {
return false;
}
const bounds = this.clientSpaceToScratchBounds(centerX, centerY, touchWidth, touchHeight);
if (bounds.left === -Infinity || bounds.bottom === -Infinity) {
return false;
}
const hits = [];
const worldPos = twgl.v3.create(0, 0, 0);
// Iterate over the scratch pixels and check if any candidate can be
@@ -1735,18 +1704,6 @@ class RenderWebGL extends EventEmitter {
dst[2] += blendAlpha * 255;
return dst;
}
/**
* @callback RenderWebGL#snapshotCallback
* @param {string} dataURI Data URI of the snapshot of the renderer
*/
/**
* @param {snapshotCallback} callback Function called in the next frame with the snapshot data
*/
requestSnapshot (callback) {
this._snapshotCallbacks.push(callback);
}
}
// :3

View File

@@ -54,24 +54,39 @@ varying vec2 v_texCoord;
// Smaller values can cause problems with "color" and "brightness" effects on some mobile devices
const float epsilon = 1e-3;
// Convert an RGB color to Hue, Chroma, and Value.
// Convert an RGB color to Hue, Saturation, and Lightness.
// All components of input and output are expected to be in the [0,1] range.
vec3 convertRGB2HCV(vec3 rgb)
{
// Based on work by Sam Hocevar and Emil Persson
vec4 P = (rgb.g < rgb.b) ? vec4(rgb.bg, -1.0, 2.0/3.0) : vec4(rgb.gb, 0.0, -1.0/3.0);
vec4 Q = (rgb.r < P.x) ? vec4(P.xyw, rgb.r) : vec4(rgb.r, P.yzx);
float C = Q.x - min(Q.w, Q.y);
float H = abs((Q.w - Q.y) / (6.0 * C + epsilon) + Q.z);
return vec3(H, C, Q.x);
}
vec3 convertRGB2HSL(vec3 rgb)
{
vec3 hcv = convertRGB2HCV(rgb);
float L = hcv.z - hcv.y * 0.5;
float S = hcv.y / (1.0 - abs(L * 2.0 - 1.0) + epsilon);
return vec3(hcv.x, S, L);
// Hue calculation has 3 cases, depending on which RGB component is largest, and one of those cases involves a "mod"
// operation. In order to avoid that "mod" we split the M==R case in two: one for G<B and one for B>G. The B>G case
// will be calculated in the negative and fed through abs() in the hue calculation at the end.
// See also: https://en.wikipedia.org/wiki/HSL_and_HSV#Hue_and_chroma
const vec4 hueOffsets = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
// temp1.xy = sort B & G (largest first)
// temp1.z = the hue offset we'll use if it turns out that R is the largest component (M==R)
// temp1.w = the hue offset we'll use if it turns out that R is not the largest component (M==G or M==B)
vec4 temp1 = rgb.b > rgb.g ? vec4(rgb.bg, hueOffsets.wz) : vec4(rgb.gb, hueOffsets.xy);
// temp2.x = the largest component of RGB ("M" / "Max")
// temp2.yw = the smaller components of RGB, ordered for the hue calculation (not necessarily sorted by magnitude!)
// temp2.z = the hue offset we'll use in the hue calculation
vec4 temp2 = rgb.r > temp1.x ? vec4(rgb.r, temp1.yzx) : vec4(temp1.xyw, rgb.r);
// m = the smallest component of RGB ("min")
float m = min(temp2.y, temp2.w);
// Chroma = M - m
float C = temp2.x - m;
// Lightness = 1/2 * (M + m)
float L = 0.5 * (temp2.x + m);
return vec3(
abs(temp2.z + (temp2.w - temp2.y) / (6.0 * C + epsilon)), // Hue
C / (1.0 - abs(2.0 * L - 1.0) + epsilon), // Saturation
L); // Lightness
}
vec3 convertHue2RGB(float hue)
@@ -85,8 +100,8 @@ vec3 convertHue2RGB(float hue)
vec3 convertHSL2RGB(vec3 hsl)
{
vec3 rgb = convertHue2RGB(hsl.x);
float C = (1.0 - abs(2.0 * hsl.z - 1.0)) * hsl.y;
return (rgb - 0.5) * C + hsl.z;
float c = (1.0 - abs(2.0 * hsl.z - 1.0)) * hsl.y;
return (rgb - 0.5) * c + hsl.z;
}
#endif // !defined(DRAW_MODE_silhouette) && (defined(ENABLE_color) || defined(ENABLE_brightness))

View File

@@ -145,16 +145,11 @@ class SVGTextBubble {
</g>`;
}
_getTextSize (textFragment) {
const svgString = this._wrapSvgFragment(textFragment);
_getTextSize () {
const svgString = this._wrapSvgFragment(this._textFragment);
if (!this._textSizeCache[svgString]) {
this._textSizeCache[svgString] = this.svgRenderer.measure(svgString);
if (this._textSizeCache[svgString].height === 0) {
// The speech bubble is empty, so use the height of a single line with content (or else it renders
// weirdly, see issue #302).
const dummyFragment = this._buildTextFragment('X');
this._textSizeCache[svgString] = this._getTextSize(dummyFragment);
}
}
return this._textSizeCache[svgString];
}
@@ -188,7 +183,7 @@ class SVGTextBubble {
let fragment = '';
const radius = 16;
const {x, y, width, height} = this._getTextSize(this._textFragment);
const {x, y, width, height} = this._getTextSize();
const padding = 10;
const fullWidth = Math.max(MIN_WIDTH, width) + (2 * padding);
const fullHeight = height + (2 * padding);

View File

@@ -7,94 +7,55 @@ const chromeless = new Chromeless();
const indexHTML = path.resolve(__dirname, 'index.html');
const testDir = (...args) => path.resolve(__dirname, 'pick-tests', ...args);
const runFile = (file, action, script) =>
const runFile = (file, script) =>
// start each test by going to the index.html, and loading the scratch file
chromeless.goto(`file://${indexHTML}`)
.setFileInput('#file', testDir(file))
// the index.html handler for file input will add a #loaded element when it
// finishes.
.wait('#loaded')
.evaluate(`function () {return (${script})(${action});}`)
.evaluate(script)
;
// immediately invoked async function to let us wait for each test to finish before starting the next.
(async () => {
const testOperation = async function (name, action, expect) {
await test(name, async t => {
await test('pick tests', async t => {
const results = await runFile('test-mouse-touch.sb2', action, boundAction => {
vm.greenFlag();
const sendResults = [];
const results = await runFile('test-mouse-touch.sb2', () => {
vm.greenFlag();
const sendResults = [];
const idToTargetName = id => {
const target = vm.runtime.targets.find(tar => tar.drawableID === id);
if (!target) {
return `[Unknown drawableID: ${id}]`;
}
return target.sprite.name;
};
const sprite = vm.runtime.targets.find(target => target.sprite.name === 'Sprite1');
const idToTargetName = id => {
const target = vm.runtime.targets.find(tar => tar.drawableID === id);
if (!target) {
return `[Unknown drawableID: ${id}]`;
}
return target.sprite.name;
};
const sprite = vm.runtime.targets.find(target => target.sprite.name === 'Sprite1');
boundAction({
sendResults,
idToTargetName,
render,
sprite
});
return sendResults;
});
t.plan(expect.length);
for (let x = 0; x < expect.length; x++) {
t.deepEqual(results[x], expect[x], expect[x][0]);
}
t.end();
sendResults.push(['center', idToTargetName(render.pick(240, 180))]);
sendResults.push(['left', idToTargetName(render.pick(200, 180))]);
sendResults.push(['over', render.drawableTouching(sprite.drawableID, 240, 180)]);
sprite.setVisible(false);
sendResults.push(['hidden sprite pick center', idToTargetName(render.pick(240, 180))]);
sendResults.push(['hidden over', render.drawableTouching(sprite.drawableID, 240, 180)]);
return sendResults;
});
};
const tests = [
{
name: 'pick Sprite1',
action: ({sendResults, render, idToTargetName}) => {
sendResults.push(['center', idToTargetName(render.pick(360, 180))]);
},
expect: [['center', 'Sprite1']]
},
{
name: 'pick Stage',
action: ({sendResults, render, idToTargetName}) => {
sendResults.push(['left', idToTargetName(render.pick(320, 180))]);
},
expect: [['left', 'Stage']]
},
{
name: 'touching Sprite1',
action: ({sprite, sendResults, render}) => {
sendResults.push(['over', render.drawableTouching(sprite.drawableID, 360, 180)]);
},
expect: [['over', true]]
},
{
name: 'pick Stage through hidden Sprite1',
action: ({sprite, sendResults, render, idToTargetName}) => {
sprite.setVisible(false);
sendResults.push(['hidden sprite pick center', idToTargetName(render.pick(360, 180))]);
},
expect: [['hidden sprite pick center', 'Stage']]
},
{
name: 'touching hidden Sprite1',
action: ({sprite, sendResults, render}) => {
sprite.setVisible(false);
sendResults.push(['hidden over', render.drawableTouching(sprite.drawableID, 360, 180)]);
},
expect: [['hidden over', true]]
const expect = [
['center', 'Sprite1'],
['left', 'Stage'],
['over', true],
['hidden sprite pick center', 'Stage'],
['hidden over', true]
];
t.plan(expect.length);
for (let x = 0; x < expect.length; x++) {
t.deepEqual(results[x], expect[x], expect[x][0]);
}
];
for (const {name, action, expect} of tests) {
await testOperation(name, action, expect);
}
t.end();
});
// close the browser window we used
await chromeless.end();