Compare commits

..

77 Commits

Author SHA1 Message Date
greenkeeper[bot]
193cb05044 chore(package): update eslint to version 6.4.0
Closes #307
2019-09-14 02:25:43 +00:00
Karishma Chadha
832b0274be Merge pull request #505 from LLK/revert-496-revert-493-revert-470-skin-alter-push
Revert "Revert "Revert "Skin alter push"""
2019-09-12 13:42:23 -04:00
Karishma Chadha
1cd9e54834 Revert "Revert "Revert "Skin alter push""" 2019-09-12 13:24:03 -04:00
Chris Willis-Ford
928cd60dd5 Merge pull request #496 from LLK/revert-493-revert-470-skin-alter-push
Revert "Revert "Skin alter push""
2019-09-04 18:14:41 -07:00
Chris Willis-Ford
30ef2b1e51 Merge pull request #497 from adroitwhiz/set-costume-size-synchronously-2
Set SVG skin size synchronously
2019-09-04 18:03:29 -07:00
Chris Willis-Ford
ad62542a52 Merge branch 'revert-493-revert-470-skin-alter-push' into set-costume-size-synchronously-2 2019-09-04 18:01:59 -07:00
DD Liu
2d4419c929 Merge pull request #443 from adroitwhiz/effects-nearest
Always use linear interpolation on vector skins with distortion effects applied
2019-09-04 17:19:52 -04:00
adroitwhiz
ad6ddd9f99 add more parentheses 2019-09-04 15:40:49 -04:00
Karishma Chadha
c3ede9c3d5 Merge pull request #495 from LLK/revert-494-revert-467-rect-init-matrix
Revert "Revert "Initialialize AABB Rectangle ""
2019-08-30 15:35:32 -04:00
Chris Willis-Ford
ab517fff51 Merge pull request #442 from adroitwhiz/pen-stamp-region-optimization
Don't _doExitDrawRegion in penStamp until we're sure we're stamping
2019-08-30 20:19:26 +01:00
Chris Willis-Ford
1371b6f685 Merge pull request #486 from adroitwhiz/fix-calculaterotationcenter
Fix calculateRotationCenter() for SVG skins
2019-08-30 20:13:50 +01:00
DD Liu
5c6997131b Merge pull request #484 from adroitwhiz/fix-cpu-render-playground
Attach V2 adapters in CPU render playground
2019-08-30 14:58:59 -04:00
Chris Willis-Ford
b4c7dbf0ea Merge pull request #441 from adroitwhiz/region-exit-fix
Clear _regionId when exiting draw region
2019-08-30 19:51:20 +01:00
Karishma Chadha
c0e5115bfc Merge pull request #444 from adroitwhiz/rectangle-clamp-fix
Fix Rectangle.Clamp()
2019-08-30 14:43:18 -04:00
DD Liu
3819b66683 Merge pull request #502 from fsih/turnOffAntiAlias
Turn off antialias
2019-08-30 11:27:30 -04:00
DD Liu
b9732c222c Fix space
Co-Authored-By: adroitwhiz <adroitwhiz@protonmail.com>
2019-08-28 19:00:16 -04:00
DD Liu
afaa758615 turn off antialias 2019-08-28 17:04:51 -04:00
DD Liu
a3a526d6a3 Merge pull request #499 from LLK/greenkeeper/scratch-svg-renderer-0.2.0-prerelease.20190820171249
Update scratch-svg-renderer to the latest version 🚀
2019-08-22 16:42:38 -04:00
DD Liu
d77afaa6c4 Update to latest svg-renderer 2019-08-22 16:28:31 -04:00
greenkeeper[bot]
3bfd4c65fb fix(package): update scratch-svg-renderer to version 0.2.0-prerelease.20190820171249 2019-08-20 17:24:08 +00:00
DD Liu
131f5372db Merge pull request #498 from LLK/revert-482-greenkeeper/scratch-svg-renderer-0.2.0-prerelease.20190715144718
Revert "Update scratch-svg-renderer to the latest version 🚀"
2019-08-19 11:43:06 -04:00
DD Liu
ef13d3bb08 Revert "Update scratch-svg-renderer to the latest version 🚀" 2019-08-19 11:40:51 -04:00
adroitwhiz
94257a4214 Set SVG skin size synchronously 2019-08-13 16:38:45 -04:00
Karishma Chadha
7c4393787b Revert "Revert "Skin alter push"" 2019-08-13 11:42:51 -04:00
Karishma Chadha
a340b8a04b Revert "Revert "Initialialize AABB Rectangle "" 2019-08-13 11:41:11 -04:00
Karishma Chadha
c2e32d2baf Merge pull request #494 from LLK/revert-467-rect-init-matrix
Revert "Initialialize AABB Rectangle "
2019-08-13 11:38:41 -04:00
Karishma Chadha
c8839b2feb Merge pull request #493 from LLK/revert-470-skin-alter-push
Revert "Skin alter push"
2019-08-13 11:38:24 -04:00
Karishma Chadha
c8f7496fba Revert "Initialialize AABB Rectangle " 2019-08-13 11:26:07 -04:00
Karishma Chadha
4a28cffcd4 Revert "Skin alter push" 2019-08-13 11:22:27 -04:00
adroitwhiz
dce90a3f56 Fix calculateRotationCenter for SVG skins 2019-07-20 17:27:45 -04:00
adroitwhiz
471d4b91a4 Attach V2 adapters in CPU render playground 2019-07-15 23:44:18 -04:00
DD Liu
d464f3e82e Merge pull request #482 from LLK/greenkeeper/scratch-svg-renderer-0.2.0-prerelease.20190715144718
Update scratch-svg-renderer to the latest version 🚀
2019-07-15 11:50:45 -04:00
DD Liu
fcda622b5a Update to latest svg renderer 2019-07-15 11:50:14 -04:00
greenkeeper[bot]
ae507dfabb fix(package): update scratch-svg-renderer to version 0.2.0-prerelease.20190715144718 2019-07-15 15:16:46 +00:00
Chris Willis-Ford
cc5fea803e Merge pull request #470 from mzgoddard/skin-alter-push
Skin alter push
2019-07-01 10:43:11 -07:00
Chris Willis-Ford
32063a2953 Merge pull request #467 from mzgoddard/rect-init-matrix
Initialialize AABB Rectangle
2019-07-01 10:31:54 -07:00
Michael "Z" Goddard
994e9be00b move the initFromModelMatrix process docs into a jsdoc tutorial 2019-06-19 18:53:05 -04:00
Michael "Z" Goddard
b7004878ff set jsdoc tutorials to come from docs 2019-06-19 18:36:17 -04:00
Michael "Z" Goddard
f187be6b31 add MockSkinPool for testing 2019-06-18 17:18:49 -04:00
Michael "Z" Goddard
14b01bd63c cache PenSkin's _canvasSize 2019-06-18 17:18:49 -04:00
Michael "Z" Goddard
24b535eb76 cache svg renderer size and view offset 2019-06-18 17:18:48 -04:00
Michael "Z" Goddard
f9b1a04d1a cache Skin.size 2019-06-18 17:18:48 -04:00
Michael "Z" Goddard
ab603ffa92 push skin alteration down from renderwebgl 2019-06-18 17:18:48 -04:00
Michael "Z" Goddard
5d7957ff9b document out how initFromModelMatrix works 2019-06-11 14:32:33 -04:00
Michael "Z" Goddard
a840089bc9 fence bounds 2019-06-11 13:05:22 -04:00
Michael "Z" Goddard
bf47f69b04 use a destination parameter for bounds; add initFromMatrixRadius
- pass bounds as a destination parameter
- add initFromMatrixRadius
- use initFromMatrixRadius in getAABB
2019-06-06 14:39:56 -04:00
Karishma Chadha
27c70a7542 Merge pull request #463 from LLK/greenkeeper/scratch-svg-renderer-0.2.0-prerelease.20190523193400
Update scratch-svg-renderer to the latest version 🚀
2019-06-05 11:02:10 -04:00
Benjamin Wheeler
a79df7af59 Merge pull request #466 from LLK/revert-423-more-circular-pen-dots
Revert "Tweak scalingVector to make dots appear to be more circular"
2019-05-30 11:58:22 -04:00
Benjamin Wheeler
ed6c707cba Revert "Tweak scalingVector to make dots appear to be more circular" 2019-05-30 11:50:54 -04:00
Chris Willis-Ford
6bdaebcb3b Merge pull request #426 from adroitwhiz/playground-improvements
Playground improvements
2019-05-28 16:10:36 -07:00
Chris Willis-Ford
8b54df18af Merge pull request #423 from ktbee/more-circular-pen-dots
Tweak scalingVector to make dots appear to be more circular
2019-05-28 15:39:34 -07:00
greenkeeper[bot]
c3d07db39a fix(package): update scratch-svg-renderer to version 0.2.0-prerelease.20190523193400 2019-05-23 19:37:48 +00:00
adroitwhiz
1b51f1f393 Merge remote-tracking branch 'upstream/develop' into effects-nearest 2019-05-23 05:35:56 -04:00
adroitwhiz
d0ed283c72 Merge remote-tracking branch 'upstream/develop' into effects-nearest 2019-05-22 16:10:30 -04:00
adroitwhiz
ab14e224d6 add default fudge min/max values 2019-05-22 05:02:44 -04:00
adroitwhiz
1a5bd39f77 replace janky boolean logic 2019-05-22 05:01:16 -04:00
adroitwhiz
e478ad4590 es6ify playground.js 2019-05-22 04:58:06 -04:00
adroitwhiz
34f265ab22 strict inequality 2019-05-22 04:52:30 -04:00
Katie Broida
9fc82a8fc3 Tweak scalingVector to make dots appear to be more circular instead of oval 2019-05-13 13:27:08 -04:00
adroitwhiz
e8d30d7629 Merge branch 'develop' of https://github.com/LLK/scratch-render into playground-improvements 2019-05-05 16:52:05 -04:00
adroitwhiz
b92354b1bf Merge branch 'develop' of https://github.com/LLK/scratch-render into playground-improvements 2019-04-23 13:21:41 -04:00
adroitwhiz
6c8b5bc2a9 Fix webpack glob 2019-04-23 13:21:40 -04:00
adroitwhiz
6646041ba4 Fix Rectangle.Clamp() 2019-04-22 08:49:20 -04:00
adroitwhiz
f9309b1ace be more s e m a n t i c 2019-04-20 08:12:22 -04:00
adroitwhiz
7599a82406 Never useNearest on distorted vector skins 2019-04-20 07:59:09 -04:00
adroitwhiz
6e755ea015 Add "disappearing pen" test 2019-04-20 02:47:25 -04:00
adroitwhiz
750f40ddf2 Exit draw region in penStamp less 2019-04-20 02:31:04 -04:00
adroitwhiz
603fd87782 Clear _regionId when exiting draw region 2019-04-20 02:27:34 -04:00
adroitwhiz
95a3c0dc6f Appease ESLint 2019-04-19 13:50:52 -04:00
adroitwhiz
05928eb400 Add very basic pen testing to playground 2019-04-19 13:44:47 -04:00
adroitwhiz
924050baaf Merge branch 'develop' of https://github.com/LLK/scratch-render into playground-improvements 2019-03-29 10:19:41 -04:00
adroitwhiz
0b9ee47fa1 Add "Scale (both)" option and fix quotes 2019-03-29 10:19:37 -04:00
adroitwhiz
3e710e66ec Move playground style rules into stylesheet 2019-03-24 03:03:51 -04:00
adroitwhiz
2f14126d0b Add stage scale slider to playground 2019-03-24 02:50:11 -04:00
adroitwhiz
4e9223adc6 More fixes for loading in playground 2019-03-24 02:43:15 -04:00
adroitwhiz
5419d3d2c3 Use updated Scratch cat SVG in playground 2019-03-24 02:42:13 -04:00
adroitwhiz
d4df59b23b Fix playground not re-reading inputs after page reload 2019-03-24 02:38:05 -04:00
15 changed files with 394 additions and 86 deletions

View File

@@ -15,6 +15,7 @@
"private": true,
"readme": "README.md",
"recurse": true,
"template": "node_modules/docdash"
"template": "node_modules/docdash",
"tutorials": "docs"
}
}

View File

@@ -0,0 +1,192 @@
# Rectangle AABB Matrix
Initialize a Rectangle to a 1 unit square centered at 0 x 0 transformed by a model matrix.
-----
Every drawable is a 1 x 1 unit square that is rotated by its direction, scaled by its skin size and scale, and offset by its rotation center and position. The square representation is made up of 4 points that are transformed by the drawable properties. Often we want a shape that simplifies those 4 points into a non-rotated shape, a axis aligned bounding box.
One approach is to compare the x and y components of each transformed vector and find the minimum and maximum x component and the minimum and maximum y component.
We can start from this approach and determine an alternative one that prodcues the same output with less work.
Starting with transforming one point, here is a 3D point, `v`, transformation by a matrix, `m`.
```js
const v0 = v[0];
const v1 = v[1];
const v2 = v[2];
const d = v0 * m[(0 * 4) + 3] + v1 * m[(1 * 4) + 3] + v2 * m[(2 * 4) + 3] + m[(3 * 4) + 3];
dst[0] = (v0 * m[(0 * 4) + 0] + v1 * m[(1 * 4) + 0] + v2 * m[(2 * 4) + 0] + m[(3 * 4) + 0]) / d;
dst[1] = (v0 * m[(0 * 4) + 1] + v1 * m[(1 * 4) + 1] + v2 * m[(2 * 4) + 1] + m[(3 * 4) + 1]) / d;
dst[2] = (v0 * m[(0 * 4) + 2] + v1 * m[(1 * 4) + 2] + v2 * m[(2 * 4) + 2] + m[(3 * 4) + 2]) / d;
```
As this is a 2D rectangle we can cancel out the third dimension, and the determinant, 'd'.
```js
const v0 = v[0];
const v1 = v[1];
dst = [
v0 * m[(0 * 4) + 0] + v1 * m[(1 * 4) + 0] + m[(3 * 4) + 0,
v0 * m[(0 * 4) + 1] + v1 * m[(1 * 4) + 1] + m[(3 * 4) + 1
];
```
Let's set the matrix points to shorter names for convenience.
```js
const m00 = m[(0 * 4) + 0];
const m01 = m[(0 * 4) + 1];
const m10 = m[(1 * 4) + 0];
const m11 = m[(1 * 4) + 1];
const m30 = m[(3 * 4) + 0];
const m31 = m[(3 * 4) + 1];
```
We need 4 points with positive and negative 0.5 values so the square has sides of length 1.
```js
let p = [0.5, 0.5];
let q = [-0.5, 0.5];
let r = [-0.5, -0.5];
let s = [0.5, -0.5];
```
Transform the points by the matrix.
```js
p = [
0.5 * m00 + 0.5 * m10 + m30,
0.5 * m01 + 0.5 * m11 + m31
];
q = [
-0.5 * m00 + -0.5 * m10 + m30,
0.5 * m01 + 0.5 * m11 + m31
];
r = [
-0.5 * m00 + -0.5 * m10 + m30,
-0.5 * m01 + -0.5 * m11 + m31
];
s = [
0.5 * m00 + 0.5 * m10 + m30,
-0.5 * m01 + -0.5 * m11 + m31
];
```
With 4 transformed points we can build the left, right, top, and bottom values for the Rectangle. Each will use the minimum or the maximum of one of the components of all points.
```js
const left = Math.min(p[0], q[0], r[0], s[0]);
const right = Math.max(p[0], q[0], r[0], s[0]);
const top = Math.max(p[1], q[1], r[1], s[1]);
const bottom = Math.min(p[1], q[1], r[1], s[1]);
```
Fill those calls with the vector expressions.
```js
const left = Math.min(
0.5 * m00 + 0.5 * m10 + m30,
-0.5 * m00 + 0.5 * m10 + m30,
-0.5 * m00 + -0.5 * m10 + m30,
0.5 * m00 + -0.5 * m10 + m30
);
const right = Math.max(
0.5 * m00 + 0.5 * m10 + m30,
-0.5 * m00 + 0.5 * m10 + m30,
-0.5 * m00 + -0.5 * m10 + m30,
0.5 * m00 + -0.5 * m10 + m30
);
const top = Math.max(
0.5 * m01 + 0.5 * m11 + m31,
-0.5 * m01 + 0.5 * m11 + m31,
-0.5 * m01 + -0.5 * m11 + m31,
0.5 * m01 + -0.5 * m11 + m31
);
const bottom = Math.min(
0.5 * m01 + 0.5 * m11 + m31,
-0.5 * m01 + 0.5 * m11 + m31,
-0.5 * m01 + -0.5 * m11 + m31,
0.5 * m01 + -0.5 * m11 + m31
);
```
Pull out the `0.5 * m??` patterns.
```js
const x0 = 0.5 * m00;
const x1 = 0.5 * m10;
const y0 = 0.5 * m01;
const y1 = 0.5 * m11;
const left = Math.min(x0 + x1 + m30, -x0 + x1 + m30, -x0 + -x1 + m30, x0 + -x1 + m30);
const right = Math.max(x0 + x1 + m30, -x0 + x1 + m30, -x0 + -x1 + m30, x0 + -x1 + m30);
const top = Math.max(y0 + y1 + m31, -y0 + y1 + m31, -y0 + -y1 + m31, y0 + -y1 + m31);
const bottom = Math.min(y0 + y1 + m31, -y0 + y1 + m31, -y0 + -y1 + m31, y0 + -y1 + m31);
```
Now each argument for the min and max calls take an expression like `(a * x0 + b * x1 + m3?)`. As each expression has the x0, x1, and m3? variables we can split the min and max calls on the addition operators. Each new call has all the coefficients of that variable.
```js
const left = Math.min(x0, -x0) + Math.min(x1, -x1) + Math.min(m30, m30);
const right = Math.max(x0, -x0) + Math.max(x1, -x1) + Math.max(m30, m30);
const top = Math.max(y0, -y0) + Math.max(y1, -y1) + Math.max(m31, m31);
const bottom = Math.min(y0, -y0) + Math.min(y1, -y1) + Math.min(m31, m31);
```
The min or max of two copies of the same value will just be that value.
```js
const left = Math.min(x0, -x0) + Math.min(x1, -x1) + m30;
const right = Math.max(x0, -x0) + Math.max(x1, -x1) + m30;
const top = Math.max(y0, -y0) + Math.max(y1, -y1) + m31;
const bottom = Math.min(y0, -y0) + Math.min(y1, -y1) + m31;
```
The max of a negative and positive variable will be the absolute value of that variable. The min of a negative and positive variable will the negated absolute value of that variable.
```js
const left = -Math.abs(x0) + -Math.abs(x1) + m30;
const right = Math.abs(x0) + Math.abs(x1) + m30;
const top = Math.abs(y0) + Math.abs(y1) + m31;
const bottom = -Math.abs(y0) + -Math.abs(y1) + m31;
```
Pulling out the negations of the absolute values, left and right as well as top and bottom are the positive or negative sum of the absolute value of the saled and rotated unit value.
```js
const left = -(Math.abs(x0) + Math.abs(x1)) + m30;
const right = Math.abs(x0) + Math.abs(x1) + m30;
const top = Math.abs(y0) + Math.abs(y1) + m31;
const bottom = -(Math.abs(y0) + Math.abs(y1)) + m31;
```
We call pull out those sums and use them twice.
```js
const x = Math.abs(x0) + Math.abs(x1);
const y = Math.abs(y0) + Math.abs(y1);
const left = -x + m30;
const right = x + m30;
const top = y + m31;
const bottom = -y + m31;
```
This lets us arrive at our goal. Inlining some of our variables we get this block that will initialize a Rectangle to a unit square transformed by a matrix.
```js
const m30 = m[(3 * 4) + 0];
const m31 = m[(3 * 4) + 1];
const x = Math.abs(0.5 * m[(0 * 4) + 0]) + Math.abs(0.5 * m[(1 * 4) + 0]);
const y = Math.abs(0.5 * m[(0 * 4) + 1]) + Math.abs(0.5 * m[(1 * 4) + 1]);
const left = -x + m30;
const right = x + m30;
const top = y + m31;
const bottom = -y + m31;
```

View File

@@ -32,13 +32,13 @@
"chromeless": "^1.5.1",
"copy-webpack-plugin": "^4.5.1",
"docdash": "^0.4.0",
"eslint": "^4.6.1",
"eslint": "^6.4.0",
"eslint-config-scratch": "^5.0.0",
"gh-pages": "^1.0.0",
"jsdoc": "^3.5.5",
"json": "^9.0.4",
"scratch-vm": "0.2.0-prerelease.20190207224121",
"tap": "^14.2.0",
"tap": "^11.0.0",
"travis-after-all": "^1.4.4",
"uglifyjs-webpack-plugin": "^1.2.5",
"webpack": "^4.8.0",
@@ -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.20190521170426",
"scratch-svg-renderer": "0.2.0-prerelease.20190822202608",
"twgl.js": "4.4.0"
}
}

View File

@@ -62,10 +62,11 @@ class BitmapSkin extends Skin {
/**
* Get the bounds of the drawable for determining its fenced position.
* @param {Array<number>} drawable - The Drawable instance this skin is using.
* @param {?Rectangle} result - Optional destination for bounds calculation.
* @return {!Rectangle} The drawable's bounds. For compatibility with Scratch 2, we always use getAABB for bitmaps.
*/
getFenceBounds (drawable) {
return drawable.getAABB();
getFenceBounds (drawable, result) {
return drawable.getAABB(result);
}
/**

View File

@@ -433,6 +433,16 @@ class Drawable {
return true;
}
// If the effect bits for mosaic, pixelate, whirl, or fisheye are set, use linear
if ((this._effectBits & (
ShaderManager.EFFECT_INFO.fisheye.mask |
ShaderManager.EFFECT_INFO.whirl.mask |
ShaderManager.EFFECT_INFO.pixelate.mask |
ShaderManager.EFFECT_INFO.mosaic.mask
)) !== 0) {
return false;
}
// We can't use nearest neighbor unless we are a multiple of 90 rotation
if (this._direction % 90 !== 0) {
return false;
@@ -451,9 +461,10 @@ class Drawable {
* This function applies the transform matrix to the known convex hull,
* and then finds the minimum box along the axes.
* Before calling this, ensure the renderer has updated convex hull points.
* @param {?Rectangle} result optional destination for bounds calculation
* @return {!Rectangle} Bounds for a tight box around the Drawable.
*/
getBounds () {
getBounds (result) {
if (this.needsConvexHullPoints()) {
throw new Error('Needs updated convex hull points before bounds calculation.');
}
@@ -462,18 +473,19 @@ class Drawable {
}
const transformedHullPoints = this._getTransformedHullPoints();
// Search through transformed points to generate box on axes.
const bounds = new Rectangle();
bounds.initFromPointsAABB(transformedHullPoints);
return bounds;
result = result || new Rectangle();
result.initFromPointsAABB(transformedHullPoints);
return result;
}
/**
* Get the precise bounds for the upper 8px slice of the Drawable.
* Used for calculating where to position a text bubble.
* Before calling this, ensure the renderer has updated convex hull points.
* @param {?Rectangle} result optional destination for bounds calculation
* @return {!Rectangle} Bounds for a tight box around a slice of the Drawable.
*/
getBoundsForBubble () {
getBoundsForBubble (result) {
if (this.needsConvexHullPoints()) {
throw new Error('Needs updated convex hull points before bubble bounds calculation.');
}
@@ -485,9 +497,9 @@ class Drawable {
const maxY = Math.max.apply(null, transformedHullPoints.map(p => p[1]));
const filteredHullPoints = transformedHullPoints.filter(p => p[1] > maxY - slice);
// Search through filtered points to generate box on axes.
const bounds = new Rectangle();
bounds.initFromPointsAABB(filteredHullPoints);
return bounds;
result = result || new Rectangle();
result.initFromPointsAABB(filteredHullPoints);
return result;
}
/**
@@ -497,35 +509,32 @@ class Drawable {
* which is tightly snapped to account for a Drawable's transparent regions.
* `getAABB` returns a much less accurate bounding box, but will be much
* faster to calculate so may be desired for quick checks/optimizations.
* @param {?Rectangle} result optional destination for bounds calculation
* @return {!Rectangle} Rough axis-aligned bounding box for Drawable.
*/
getAABB () {
getAABB (result) {
if (this._transformDirty) {
this._calculateTransform();
}
const tm = this._uniforms.u_modelMatrix;
const bounds = new Rectangle();
bounds.initFromPointsAABB([
twgl.m4.transformPoint(tm, [-0.5, -0.5, 0]),
twgl.m4.transformPoint(tm, [0.5, -0.5, 0]),
twgl.m4.transformPoint(tm, [-0.5, 0.5, 0]),
twgl.m4.transformPoint(tm, [0.5, 0.5, 0])
]);
return bounds;
result = result || new Rectangle();
result.initFromModelMatrix(tm);
return result;
}
/**
* Return the best Drawable bounds possible without performing graphics queries.
* I.e., returns the tight bounding box when the convex hull points are already
* known, but otherwise return the rough AABB of the Drawable.
* @param {?Rectangle} result optional destination for bounds calculation
* @return {!Rectangle} Bounds for the Drawable.
*/
getFastBounds () {
getFastBounds (result) {
this.updateMatrix();
if (!this.needsConvexHullPoints()) {
return this.getBounds();
return this.getBounds(result);
}
return this.getAABB();
return this.getAABB(result);
}
/**

View File

@@ -54,6 +54,31 @@ class Rectangle {
}
}
/**
* Initialize a Rectangle to a 1 unit square centered at 0 x 0 transformed
* by a model matrix.
* @param {Array.<number>} m A 4x4 matrix to transform the rectangle by.
* @tutorial Rectangle-AABB-Matrix
*/
initFromModelMatrix (m) {
// In 2D space, we will soon use the 2x2 "top left" scale and rotation
// submatrix, while we store and the 1x2 "top right" that position
// vector.
const m30 = m[(3 * 4) + 0];
const m31 = m[(3 * 4) + 1];
// "Transform" a (0.5, 0.5) vector by the scale and rotation matrix but
// sum the absolute of each component instead of use the signed values.
const x = Math.abs(0.5 * m[(0 * 4) + 0]) + Math.abs(0.5 * m[(1 * 4) + 0]);
const y = Math.abs(0.5 * m[(0 * 4) + 1]) + Math.abs(0.5 * m[(1 * 4) + 1]);
// And adding them to the position components initializes our Rectangle.
this.left = -x + m30;
this.right = x + m30;
this.top = y + m31;
this.bottom = -y + m31;
}
/**
* Determine if this Rectangle intersects some other.
* Note that this is a comparison assuming the Rectangle was
@@ -98,11 +123,11 @@ class Rectangle {
this.right = Math.min(this.right, right);
this.bottom = Math.max(this.bottom, bottom);
this.top = Math.min(this.top, top);
// Ensure rectangle coordinates in order.
this.left = Math.min(this.left, this.right);
this.right = Math.max(this.right, this.left);
this.bottom = Math.min(this.bottom, this.top);
this.top = Math.max(this.top, this.bottom);
this.left = Math.min(this.left, right);
this.right = Math.max(this.right, left);
this.bottom = Math.min(this.bottom, top);
this.top = Math.max(this.top, bottom);
}
/**

View File

@@ -16,6 +16,7 @@ const log = require('./util/log');
const __isTouchingDrawablesPoint = twgl.v3.create();
const __candidatesBounds = new Rectangle();
const __fenceBounds = new Rectangle();
const __touchingColor = new Uint8ClampedArray(4);
const __blendColor = new Uint8ClampedArray(4);
@@ -104,7 +105,7 @@ class RenderWebGL extends EventEmitter {
* @private
*/
static _getContext (canvas) {
return twgl.getWebGLContext(canvas, {alpha: false, stencil: true});
return twgl.getWebGLContext(canvas, {alpha: false, stencil: true, antialias: false});
}
/**
@@ -1357,7 +1358,7 @@ class RenderWebGL extends EventEmitter {
const dx = x - drawable._position[0];
const dy = y - drawable._position[1];
const aabb = drawable._skin.getFenceBounds(drawable);
const aabb = drawable._skin.getFenceBounds(drawable, __fenceBounds);
const inset = Math.floor(Math.min(aabb.width, aabb.height) / 2);
const sx = this._xRight - Math.min(FENCE_WIDTH, inset);
@@ -1416,8 +1417,6 @@ class RenderWebGL extends EventEmitter {
* @param {int} stampID - the unique ID of the Drawable to use as the stamp.
*/
penStamp (penSkinID, stampID) {
this._doExitDrawRegion();
const stampDrawable = this._allDrawables[stampID];
if (!stampDrawable) {
return;
@@ -1428,6 +1427,8 @@ class RenderWebGL extends EventEmitter {
return;
}
this._doExitDrawRegion();
const skin = /** @type {PenSkin} */ this._allSkins[penSkinID];
const gl = this._gl;
@@ -1548,6 +1549,7 @@ class RenderWebGL extends EventEmitter {
this._exitRegion();
}
this._exitRegion = null;
this._regionId = null;
}
/**
@@ -1627,14 +1629,14 @@ class RenderWebGL extends EventEmitter {
}
twgl.setUniforms(currentShader, uniforms);
/* adjust blend function for this skin */
if (drawable.skin.hasPremultipliedAlpha){
gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
} else {
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
}
twgl.drawBufferInfo(gl, this._bufferInfo, gl.TRIANGLES);
}

View File

@@ -146,10 +146,11 @@ class Skin extends EventEmitter {
/**
* Get the bounds of the drawable for determining its fenced position.
* @param {Array<number>} drawable - The Drawable instance this skin is using.
* @param {?Rectangle} result - Optional destination for bounds calculation.
* @return {!Rectangle} The drawable's bounds.
*/
getFenceBounds (drawable) {
return drawable.getFastBounds();
getFenceBounds (drawable, result) {
return drawable.getFastBounds(result);
}
/**

View File

@@ -3,13 +3,11 @@
<head>
<meta charset="UTF-8">
<title>Scratch WebGL rendering demo</title>
<style>
#scratch-stage { width: 480px; }
</style>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body style="background: lightsteelblue">
<canvas id="scratch-stage" width="10" height="10" style="border:3px dashed black"></canvas>
<canvas id="debug-canvas" width="10" height="10" style="border:3px dashed red"></canvas>
<body>
<canvas id="scratch-stage" width="10" height="10"></canvas>
<canvas id="debug-canvas" width="10" height="10"></canvas>
<p>
<label for="fudgeproperty">Property to tweak:</label>
<select id="fudgeproperty">
@@ -18,6 +16,7 @@
<option value="direction">Direction</option>
<option value="scalex">Scale X</option>
<option value="scaley">Scale Y</option>
<option value="scaleboth">Scale (both dimensions)</option>
<option value="color">Color</option>
<option value="fisheye">Fisheye</option>
<option value="whirl">Whirl</option>
@@ -30,8 +29,12 @@
<input type="range" id="fudge" style="width:50%" value="90" min="-90" max="270" step="any">
</p>
<p>
<label for="fudgeMin">Min:</label><input id="fudgeMin" type="number">
<label for="fudgeMax">Max:</label><input id="fudgeMax" type="number">
<label for="stage-scale">Stage scale:</label>
<input type="range" style="width:50%" id="stage-scale" value="1" min="1" max="2.5" step="any">
</p>
<p>
<label for="fudgeMin">Min:</label><input id="fudgeMin" type="number" value="0">
<label for="fudgeMax">Max:</label><input id="fudgeMax" type="number" value="200">
</p>
<script src="playground.js"></script>
</body>

View File

@@ -1,26 +1,32 @@
const ScratchRender = require('../RenderWebGL');
const getMousePosition = require('./getMousePosition');
var canvas = document.getElementById('scratch-stage');
var fudge = 90;
var renderer = new ScratchRender(canvas);
const canvas = document.getElementById('scratch-stage');
let fudge = 90;
const renderer = new ScratchRender(canvas);
renderer.setLayerGroupOrdering(['group1']);
var drawableID = renderer.createDrawable('group1');
const drawableID = renderer.createDrawable('group1');
renderer.updateDrawableProperties(drawableID, {
position: [0, 0],
scale: [100, 100],
direction: 90
});
var drawableID2 = renderer.createDrawable('group1');
var wantBitmapSkin = false;
const WantedSkinType = {
bitmap: 'bitmap',
vector: 'vector',
pen: 'pen'
};
const drawableID2 = renderer.createDrawable('group1');
const wantedSkin = WantedSkinType.vector;
// Bitmap (squirrel)
var image = new Image();
const image = new Image();
image.addEventListener('load', () => {
var bitmapSkinId = renderer.createBitmapSkin(image);
if (wantBitmapSkin) {
const bitmapSkinId = renderer.createBitmapSkin(image);
if (wantedSkin === WantedSkinType.bitmap) {
renderer.updateDrawableProperties(drawableID2, {
skinId: bitmapSkinId
});
@@ -30,44 +36,83 @@ image.crossOrigin = 'anonymous';
image.src = 'https://cdn.assets.scratch.mit.edu/internalapi/asset/7e24c99c1b853e52f8e7f9004416fa34.png/get/';
// SVG (cat 1-a)
var xhr = new XMLHttpRequest();
const xhr = new XMLHttpRequest();
xhr.addEventListener('load', function () {
var skinId = renderer.createSVGSkin(xhr.responseText);
if (!wantBitmapSkin) {
const skinId = renderer.createSVGSkin(xhr.responseText);
if (wantedSkin === WantedSkinType.vector) {
renderer.updateDrawableProperties(drawableID2, {
skinId: skinId
});
}
});
xhr.open('GET', 'https://cdn.assets.scratch.mit.edu/internalapi/asset/f88bf1935daea28f8ca098462a31dbb0.svg/get/');
xhr.open('GET', 'https://cdn.assets.scratch.mit.edu/internalapi/asset/b7853f557e4426412e64bb3da6531a99.svg/get/');
xhr.send();
var posX = 0;
var posY = 0;
var scaleX = 100;
var scaleY = 100;
var fudgeProperty = 'posx';
if (wantedSkin === WantedSkinType.pen) {
const penSkinID = renderer.createPenSkin();
const fudgePropertyInput = document.getElementById('fudgeproperty');
fudgePropertyInput.addEventListener('change', event => {
fudgeProperty = event.target.value;
});
renderer.updateDrawableProperties(drawableID2, {
skinId: penSkinID
});
canvas.addEventListener('click', event => {
let rect = canvas.getBoundingClientRect();
let x = event.clientX - rect.left;
let y = event.clientY - rect.top;
renderer.penLine(penSkinID, {
color4f: [Math.random(), Math.random(), Math.random(), 1],
diameter: 8
},
x - 240, 180 - y, (Math.random() * 480) - 240, (Math.random() * 360) - 180);
});
}
let posX = 0;
let posY = 0;
let scaleX = 100;
let scaleY = 100;
let fudgeProperty = 'posx';
const fudgeInput = document.getElementById('fudge');
const fudgePropertyInput = document.getElementById('fudgeproperty');
const fudgeMinInput = document.getElementById('fudgeMin');
fudgeMinInput.addEventListener('change', event => {
fudgeInput.min = event.target.valueAsNumber;
});
const fudgeMaxInput = document.getElementById('fudgeMax');
fudgeMaxInput.addEventListener('change', event => {
/* eslint require-jsdoc: 0 */
const updateFudgeProperty = event => {
fudgeProperty = event.target.value;
};
const updateFudgeMin = event => {
fudgeInput.min = event.target.valueAsNumber;
};
const updateFudgeMax = event => {
fudgeInput.max = event.target.valueAsNumber;
});
};
fudgePropertyInput.addEventListener('change', updateFudgeProperty);
fudgePropertyInput.addEventListener('init', updateFudgeProperty);
fudgeMinInput.addEventListener('change', updateFudgeMin);
fudgeMinInput.addEventListener('init', updateFudgeMin);
fudgeMaxInput.addEventListener('change', updateFudgeMax);
fudgeMaxInput.addEventListener('init', updateFudgeMax);
// Ugly hack to properly set the values of the inputs on page load,
// since they persist across reloads, at least in Firefox.
// The best ugly hacks are the ones that reduce code duplication!
fudgePropertyInput.dispatchEvent(new CustomEvent('init'));
fudgeMinInput.dispatchEvent(new CustomEvent('init'));
fudgeMaxInput.dispatchEvent(new CustomEvent('init'));
fudgeInput.dispatchEvent(new CustomEvent('init'));
const handleFudgeChanged = function (event) {
fudge = event.target.valueAsNumber;
var props = {};
const props = {};
switch (fudgeProperty) {
case 'posx':
props.position = [fudge, posY];
@@ -88,6 +133,11 @@ const handleFudgeChanged = function (event) {
props.scale = [scaleX, fudge];
scaleY = fudge;
break;
case 'scaleboth':
props.scale = [fudge, fudge];
scaleX = fudge;
scaleY = fudge;
break;
case 'color':
props.color = fudge;
break;
@@ -112,17 +162,28 @@ const handleFudgeChanged = function (event) {
}
renderer.updateDrawableProperties(drawableID2, props);
};
fudgeInput.addEventListener('input', handleFudgeChanged);
fudgeInput.addEventListener('change', handleFudgeChanged);
fudgeInput.addEventListener('init', handleFudgeChanged);
const updateStageScale = event => {
renderer.resize(480 * event.target.valueAsNumber, 360 * event.target.valueAsNumber);
};
const stageScaleInput = document.getElementById('stage-scale');
stageScaleInput.addEventListener('input', updateStageScale);
stageScaleInput.addEventListener('change', updateStageScale);
canvas.addEventListener('mousemove', event => {
var mousePos = getMousePosition(event, canvas);
const mousePos = getMousePosition(event, canvas);
renderer.extractColor(mousePos.x, mousePos.y, 30);
});
canvas.addEventListener('click', event => {
var mousePos = getMousePosition(event, canvas);
var pickID = renderer.pick(mousePos.x, mousePos.y);
const mousePos = getMousePosition(event, canvas);
const pickID = renderer.pick(mousePos.x, mousePos.y);
console.log('You clicked on ' + (pickID < 0 ? 'nothing' : 'ID# ' + pickID));
if (pickID >= 0) {
console.dir(renderer.extractDrawable(pickID, mousePos.x, mousePos.y));
@@ -137,5 +198,5 @@ const drawStep = function () {
};
drawStep();
var debugCanvas = /** @type {canvas} */ document.getElementById('debug-canvas');
const debugCanvas = /** @type {canvas} */ document.getElementById('debug-canvas');
renderer.setDebugCanvas(debugCanvas);

View File

@@ -3,6 +3,7 @@
<head>
<meta charset="UTF-8">
<title>Scratch WebGL Query Playground</title>
<link rel="stylesheet" type="text/css" href="style.css">
<style>
input[type=range][orient=vertical] {
writing-mode: bt-lr; /* IE */
@@ -11,8 +12,6 @@
padding: 0 0.5rem;
}
canvas {
border: 3px dashed black;
/* https://stackoverflow.com/a/7665647 */
image-rendering: optimizeSpeed; /* Older versions of FF */
image-rendering: -moz-crisp-edges; /* FF 6.0+ */
@@ -23,7 +22,7 @@
}
</style>
</head>
<body style="background: lightsteelblue">
<body>
<div>
<fieldset>
<legend>Query Canvases</legend>
@@ -63,7 +62,7 @@
<input id="cursorY" type="range" orient="vertical" step="0.25" value="0" />
</td>
<td>
<canvas id="renderCanvas" width="480" height="360" style="border:3px dashed black"></canvas>
<canvas id="renderCanvas" width="480" height="360"></canvas>
</td>
</tr>
</table>

11
src/playground/style.css Normal file
View File

@@ -0,0 +1,11 @@
body {
background: lightsteelblue;
}
canvas {
border: 3px dashed black;
}
#debug-canvas {
border-color: red;
}

View File

@@ -1,6 +1,7 @@
<body>
<script src="../../node_modules/scratch-vm/dist/web/scratch-vm.js"></script>
<script src="../../node_modules/scratch-storage/dist/web/scratch-storage.js"></script>
<script src="../../node_modules/scratch-svg-renderer/dist/web/scratch-svg-renderer.js"></script>
<!-- note: this uses the BUILT version of scratch-render! make sure to npm run build -->
<script src="../../dist/web/scratch-render.js"></script>
@@ -21,6 +22,8 @@
vm.attachStorage(storage);
vm.attachRenderer(render);
vm.attachV2SVGAdapter(new ScratchSVGRenderer.SVGRenderer());
vm.attachV2BitmapAdapter(new ScratchSVGRenderer.BitmapAdapter());
document.getElementById('file').addEventListener('click', e => {
document.body.removeChild(document.getElementById('loaded'));

Binary file not shown.

View File

@@ -51,7 +51,7 @@ module.exports = [
new CopyWebpackPlugin([
{
context: 'src/playground',
from: '*.html'
from: '*.+(html|css)'
}
])
])