Move useNearest to skin classes

This commit is contained in:
adroitwhiz 2020-03-12 06:36:33 -04:00
parent a7df2b2e8e
commit 97605f9e55
6 changed files with 50 additions and 59 deletions

View File

@ -33,13 +33,6 @@ class BitmapSkin extends Skin {
super.dispose();
}
/**
* @returns {boolean} true for a raster-style skin (like a BitmapSkin), false for vector-style (like SVGSkin).
*/
get isRaster () {
return true;
}
/**
* @return {Array<number>} the "native" size, in texels, of this skin.
*/

View File

@ -489,40 +489,6 @@ class Drawable {
return this.skin.isTouchingLinear(getLocalPosition(this, vec));
}
/**
* Should the drawable use NEAREST NEIGHBOR or LINEAR INTERPOLATION mode
* @param {?Array<Number>} scale Optionally, the screen-space scale of the drawable.
* @return {boolean} True if the drawable should use nearest-neighbor interpolation.
*/
useNearest (scale = this.scale) {
// Raster skins (bitmaps) should always prefer nearest neighbor
if (this.skin.isRaster) {
return true;
}
// If the effect bits for mosaic, pixelate, whirl, or fisheye are set, use linear
if ((this.enabledEffects & (
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;
}
// If the scale of the skin is very close to 100 (0.99999 variance is okay I guess)
if (Math.abs(scale[0]) > 99 && Math.abs(scale[0]) < 101 &&
Math.abs(scale[1]) > 99 && Math.abs(scale[1]) < 101) {
return true;
}
return false;
}
/**
* Get the precise bounds for a Drawable.
* This function applies the transform matrix to the known convex hull,
@ -660,7 +626,7 @@ class Drawable {
if (this.skin) {
this.skin.updateSilhouette(this._scale);
if (this.useNearest()) {
if (this.skin.useNearest(this._scale)) {
this.isTouching = this._isTouchingNearest;
} else {
this.isTouching = this._isTouchingLinear;
@ -734,10 +700,10 @@ class Drawable {
dst[3] = 0;
return dst;
}
const textColor =
// commenting out to only use nearest for now
// drawable.useNearest() ?
// drawable.skin.useNearest(drawable._scale) ?
drawable.skin._silhouette.colorAtNearest(localPosition, dst);
// : drawable.skin._silhouette.colorAtLinear(localPosition, dst);

View File

@ -151,13 +151,6 @@ class PenSkin extends Skin {
super.dispose();
}
/**
* @returns {boolean} true for a raster-style skin (like a BitmapSkin), false for vector-style (like SVGSkin).
*/
get isRaster () {
return true;
}
/**
* @return {Array<number>} the "native" size, in texels, of this skin. [width, height]
*/
@ -165,6 +158,12 @@ class PenSkin extends Skin {
return [this._canvas.width, this._canvas.height];
}
useNearest (scale) {
// Use nearest-neighbor interpolation when scaling up the pen skin-- this matches Scratch 2.0.
// When scaling it down, use linear interpolation to avoid giving pen lines a "dashed" appearance.
return Math.max(scale[0], scale[1]) >= 100;
}
/**
* @return {WebGLTexture} The GL texture representation of this skin when drawing at the given size.
* @param {int} pixelsWide - The width that the skin will be rendered at, in GPU pixels.

View File

@ -1899,7 +1899,7 @@ class RenderWebGL extends EventEmitter {
if (uniforms.u_skin) {
twgl.setTextureParameters(
gl, uniforms.u_skin, {minMag: drawable.useNearest(drawableScale) ? gl.NEAREST : gl.LINEAR}
gl, uniforms.u_skin, {minMag: drawable.skin.useNearest(drawableScale) ? gl.NEAREST : gl.LINEAR}
);
}

View File

@ -2,6 +2,7 @@ const twgl = require('twgl.js');
const Skin = require('./Skin');
const SvgRenderer = require('scratch-svg-renderer').SVGRenderer;
const ShaderManager = require('./ShaderManager');
const MAX_TEXTURE_DIMENSION = 2048;
@ -58,6 +59,33 @@ class SVGSkin extends Skin {
return this._svgRenderer.size;
}
// Because SVG skins' bounding boxes are currently not pixel-aligned, the idea here is to hide blurriness
// by using nearest-neighbor scaling if one screen-space pixel is "close enough" to one texture pixel.
useNearest (scale) {
// If the effect bits for mosaic, pixelate, whirl, or fisheye are set, use linear
if ((this.enabledEffects & (
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;
}
// If the scale of the skin is very close to 100 (0.99999 variance is okay I guess)
// TODO: Make this check more precise. Mipmaps complicate this somewhat.
if (Math.abs(scale[0]) > 99 && Math.abs(scale[0]) < 101 &&
Math.abs(scale[1]) > 99 && Math.abs(scale[1]) < 101) {
return true;
}
return false;
}
/**
* Create a MIP for a given scale.
* @param {number} scale - The relative size of the MIP

View File

@ -59,13 +59,6 @@ class Skin extends EventEmitter {
this._id = RenderConstants.ID_NONE;
}
/**
* @returns {boolean} true for a raster-style skin (like a BitmapSkin), false for vector-style (like SVGSkin).
*/
get isRaster () {
return false;
}
/**
* @return {int} the unique ID for this Skin.
*/
@ -88,6 +81,18 @@ class Skin extends EventEmitter {
return [0, 0];
}
/**
* Should this skin's texture be filtered with nearest-neighbor or linear interpolation at the given scale?
* @param {?Array<Number>} scale The screen-space X and Y scaling factors at which this skin's texture will be
* displayed, as percentages (100 means 1 "native size" unit is 1 screen pixel; 200 means 2 screen pixels, etc).
* @return {boolean} True if this skin's texture, as returned by {@link getTexture}, should be filtered with
* nearest-neighbor interpolation.
*/
// eslint-disable-next-line no-unused-vars
useNearest (scale) {
return true;
}
/**
* Get the center of the current bounding box
* @return {Array<number>} the center of the current bounding box