Skip to content

Commit 0af5331

Browse files
committed
Move useNearest to skin classes
1 parent 1c0928f commit 0af5331

File tree

6 files changed

+51
-60
lines changed

6 files changed

+51
-60
lines changed

src/BitmapSkin.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,6 @@ class BitmapSkin extends Skin {
3333
super.dispose();
3434
}
3535

36-
/**
37-
* @returns {boolean} true for a raster-style skin (like a BitmapSkin), false for vector-style (like SVGSkin).
38-
*/
39-
get isRaster () {
40-
return true;
41-
}
42-
4336
/**
4437
* @return {Array<number>} the "native" size, in texels, of this skin.
4538
*/

src/Drawable.js

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -465,48 +465,14 @@ class Drawable {
465465

466466
const localPosition = getLocalPosition(this, vec);
467467

468-
// We're not passing in a scale to useNearest, but that's okay because "touching" queries
469-
// happen at the "native" size anyway.
470-
if (this.useNearest()) {
468+
// "touching" queries always occur at the "native" size, so it's fine to just pass in this._scale with no
469+
// screen-space scaling factors.
470+
if (this.skin.useNearest(this._scale)) {
471471
return this.skin.isTouchingNearest(localPosition);
472472
}
473473
return this.skin.isTouchingLinear(localPosition);
474474
}
475475

476-
/**
477-
* Should the drawable use NEAREST NEIGHBOR or LINEAR INTERPOLATION mode
478-
* @param {?Array<Number>} scale Optionally, the screen-space scale of the drawable.
479-
* @return {boolean} True if the drawable should use nearest-neighbor interpolation.
480-
*/
481-
useNearest (scale = this.scale) {
482-
// Raster skins (bitmaps) should always prefer nearest neighbor
483-
if (this.skin.isRaster) {
484-
return true;
485-
}
486-
487-
// If the effect bits for mosaic, pixelate, whirl, or fisheye are set, use linear
488-
if ((this.enabledEffects & (
489-
ShaderManager.EFFECT_INFO.fisheye.mask |
490-
ShaderManager.EFFECT_INFO.whirl.mask |
491-
ShaderManager.EFFECT_INFO.pixelate.mask |
492-
ShaderManager.EFFECT_INFO.mosaic.mask
493-
)) !== 0) {
494-
return false;
495-
}
496-
497-
// We can't use nearest neighbor unless we are a multiple of 90 rotation
498-
if (this._direction % 90 !== 0) {
499-
return false;
500-
}
501-
502-
// If the scale of the skin is very close to 100 (0.99999 variance is okay I guess)
503-
if (Math.abs(scale[0]) > 99 && Math.abs(scale[0]) < 101 &&
504-
Math.abs(scale[1]) > 99 && Math.abs(scale[1]) < 101) {
505-
return true;
506-
}
507-
return false;
508-
}
509-
510476
/**
511477
* Get the precise bounds for a Drawable.
512478
* This function applies the transform matrix to the known convex hull,
@@ -712,7 +678,7 @@ class Drawable {
712678
}
713679
const textColor =
714680
// commenting out to only use nearest for now
715-
// drawable.useNearest() ?
681+
// drawable.skin.useNearest(drawable._scale) ?
716682
drawable.skin._silhouette.colorAtNearest(localPosition, dst);
717683
// : drawable.skin._silhouette.colorAtLinear(localPosition, dst);
718684

src/PenSkin.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -151,20 +151,19 @@ class PenSkin extends Skin {
151151
super.dispose();
152152
}
153153

154-
/**
155-
* @returns {boolean} true for a raster-style skin (like a BitmapSkin), false for vector-style (like SVGSkin).
156-
*/
157-
get isRaster () {
158-
return true;
159-
}
160-
161154
/**
162155
* @return {Array<number>} the "native" size, in texels, of this skin. [width, height]
163156
*/
164157
get size () {
165158
return [this._canvas.width, this._canvas.height];
166159
}
167160

161+
useNearest (scale) {
162+
// Use nearest-neighbor interpolation when scaling up the pen skin-- this matches Scratch 2.0.
163+
// When scaling it down, use linear interpolation to avoid giving pen lines a "dashed" appearance.
164+
return Math.max(scale[0], scale[1]) >= 100;
165+
}
166+
168167
/**
169168
* @return {WebGLTexture} The GL texture representation of this skin when drawing at the given size.
170169
* @param {int} pixelsWide - The width that the skin will be rendered at, in GPU pixels.

src/RenderWebGL.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1752,7 +1752,7 @@ class RenderWebGL extends EventEmitter {
17521752

17531753
if (uniforms.u_skin) {
17541754
twgl.setTextureParameters(
1755-
gl, uniforms.u_skin, {minMag: drawable.useNearest(drawableScale) ? gl.NEAREST : gl.LINEAR}
1755+
gl, uniforms.u_skin, {minMag: drawable.skin.useNearest(drawableScale) ? gl.NEAREST : gl.LINEAR}
17561756
);
17571757
}
17581758

src/SVGSkin.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const twgl = require('twgl.js');
22

33
const Skin = require('./Skin');
44
const SvgRenderer = require('scratch-svg-renderer').SVGRenderer;
5+
const ShaderManager = require('./ShaderManager');
56

67
const MAX_TEXTURE_DIMENSION = 2048;
78
const MIN_TEXTURE_SCALE = 1 / 256;
@@ -58,6 +59,33 @@ class SVGSkin extends Skin {
5859
return this._svgRenderer.size;
5960
}
6061

62+
// Because SVG skins' bounding boxes are currently not pixel-aligned, the idea here is to hide blurriness
63+
// by using nearest-neighbor scaling if one screen-space pixel is "close enough" to one texture pixel.
64+
useNearest (scale) {
65+
// If the effect bits for mosaic, pixelate, whirl, or fisheye are set, use linear
66+
if ((this.enabledEffects & (
67+
ShaderManager.EFFECT_INFO.fisheye.mask |
68+
ShaderManager.EFFECT_INFO.whirl.mask |
69+
ShaderManager.EFFECT_INFO.pixelate.mask |
70+
ShaderManager.EFFECT_INFO.mosaic.mask
71+
)) !== 0) {
72+
return false;
73+
}
74+
75+
// We can't use nearest neighbor unless we are a multiple of 90 rotation
76+
if (this._direction % 90 !== 0) {
77+
return false;
78+
}
79+
80+
// If the scale of the skin is very close to 100 (0.99999 variance is okay I guess)
81+
// TODO: Make this check more precise. Mipmaps complicate this somewhat.
82+
if (Math.abs(scale[0]) > 99 && Math.abs(scale[0]) < 101 &&
83+
Math.abs(scale[1]) > 99 && Math.abs(scale[1]) < 101) {
84+
return true;
85+
}
86+
return false;
87+
}
88+
6189
/**
6290
* Set the origin, in object space, about which this Skin should rotate.
6391
* @param {number} x - The x coordinate of the new rotation center.

src/Skin.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,6 @@ class Skin extends EventEmitter {
7272
this._id = RenderConstants.ID_NONE;
7373
}
7474

75-
/**
76-
* @returns {boolean} true for a raster-style skin (like a BitmapSkin), false for vector-style (like SVGSkin).
77-
*/
78-
get isRaster () {
79-
return false;
80-
}
81-
8275
/**
8376
* @return {int} the unique ID for this Skin.
8477
*/
@@ -101,6 +94,18 @@ class Skin extends EventEmitter {
10194
return [0, 0];
10295
}
10396

97+
/**
98+
* Should this skin's texture be filtered with nearest-neighbor or linear interpolation at the given scale?
99+
* @param {?Array<Number>} scale The screen-space X and Y scaling factors at which this skin's texture will be
100+
* displayed, as percentages (100 means 1 "native size" unit is 1 screen pixel; 200 means 2 screen pixels, etc).
101+
* @return {boolean} True if this skin's texture, as returned by {@link getTexture}, should be filtered with
102+
* nearest-neighbor interpolation.
103+
*/
104+
// eslint-disable-next-line no-unused-vars
105+
useNearest (scale) {
106+
return true;
107+
}
108+
104109
/**
105110
* Set the origin, in object space, about which this Skin should rotate.
106111
* @param {number} x - The x coordinate of the new rotation center.

0 commit comments

Comments
 (0)