Generate docs from src, publish to gh-pages

Fix any broken JSDoc syntax. Unfortunately there is no way to document tuples like `{[int, int]}` for a `[width, height]` array. We could possibly fix this and make the code more readable with `{width: number, height: number}` instead of tuples.

Remove single `@fileoverview` from Rectangle.js, since it was the only file with one and was weird to have that one module show up on the docs home page.

Add a `docs` script to `package.json`, run it from `npm test`, so invalid docs will cause tests to fail (eventually we may want to start using eslint-plugin-jsdoc to catch these errors with the linter alone).
This commit is contained in:
Ray Schamp 2017-02-19 23:57:55 -05:00
parent b7d5610b23
commit 3c6511d94e
13 changed files with 159 additions and 85 deletions

1
.gitignore vendored
View file

@ -16,3 +16,4 @@ npm-*
/dist
/playground/scratch-render.js
/playground/scratch-render.js.map
/playground/docs

20
.jsdoc.json Normal file
View file

@ -0,0 +1,20 @@
{
"plugins": ["plugins/markdown"],
"templates": {
"default": {
"includeDate": false,
"outputSourceFiles": false
}
},
"source": {
"include": ["src"]
},
"opts": {
"destination": "playground/docs",
"pedantic": true,
"private": true,
"readme": "README.md",
"recurse": true,
"template": "node_modules/docdash"
}
}

View file

@ -11,14 +11,15 @@
},
"main": "./dist/node/scratch-render.js",
"scripts": {
"build": "./node_modules/.bin/webpack --progress --colors",
"lint": "./node_modules/.bin/eslint .",
"build": "webpack --progress --colors",
"docs": "jsdoc -c .jsdoc.json",
"lint": "eslint .",
"prepublish": "npm run build",
"prepublish-watch": "npm run watch",
"start": "./node_modules/.bin/webpack-dev-server",
"test": "npm run lint",
"version": "./node_modules/.bin/json -f package.json -I -e \"this.repository.sha = '$(git log -n1 --pretty=format:%H)'\"",
"watch": "./node_modules/.bin/webpack --progress --colors --watch --watch-poll"
"start": "webpack-dev-server",
"test": "npm run lint && npm run docs",
"version": "json -f package.json -I -e \"this.repository.sha = '$(git log -n1 --pretty=format:%H)'\"",
"watch": "webpack --progress --colors --watch --watch-poll"
},
"devDependencies": {
"babel-core": "6.22.1",
@ -27,10 +28,12 @@
"babel-polyfill": "6.22.0",
"babel-preset-es2015": "6.22.0",
"base64-loader": "1.0.0",
"docdash": "0.4.0",
"eslint": "3.16.0",
"eslint-config-scratch": "3.1.0",
"gh-pages": "0.12.0",
"hull.js": "0.2.10",
"jsdoc": "3.4.3",
"json": "9.0.4",
"json-loader": "0.5.4",
"lodash.defaultsdeep": "4.6.0",

View file

@ -5,6 +5,7 @@ const Skin = require('./Skin');
class BitmapSkin extends Skin {
/**
* Create a new Bitmap Skin.
* @extends Skin
* @param {!int} id - The ID for this Skin.
* @param {!RenderWebGL} renderer - The renderer which will use this skin.
*/
@ -20,7 +21,7 @@ class BitmapSkin extends Skin {
/** @type {WebGLTexture} */
this._texture = null;
/** @type {[int, int]} */
/** @type {Array<int>} */
this._textureSize = [0, 0];
}
@ -36,14 +37,14 @@ class BitmapSkin extends Skin {
}
/**
* @return {[number,number]} the "native" size, in texels, of this skin.
* @return {Array<number>} the "native" size, in texels, of this skin.
*/
get size () {
return [this._textureSize[0] / this._costumeResolution, this._textureSize[1] / this._costumeResolution];
}
/**
* @param {[number,number]} scale - The scaling factors to be used.
* @param {Array<number>} scale - The scaling factors to be used.
* @return {WebGLTexture} The GL texture representation of this skin when drawing at the given scale.
*/
// eslint-disable-next-line no-unused-vars
@ -55,8 +56,9 @@ class BitmapSkin extends Skin {
* Set the contents of this skin to a snapshot of the provided bitmap data.
* @param {ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} bitmapData - new contents for this skin.
* @param {int} [costumeResolution=1] - The resolution to use for this bitmap.
* @param {number[]=} rotationCenter - Optional rotation center for the bitmap. If not supplied, it will be
* @param {Array<number>} [rotationCenter] - Optional rotation center for the bitmap. If not supplied, it will be
* calculated from the bounding box
* @fires Skin.event:WasAltered
*/
setBitmap (bitmapData, costumeResolution, rotationCenter) {
const gl = this._renderer.gl;
@ -68,7 +70,8 @@ class BitmapSkin extends Skin {
const textureOptions = {
auto: true,
mag: gl.NEAREST,
min: gl.NEAREST, // TODO: mipmaps, linear (except pixelate)
/** @todo mipmaps, linear (except pixelate) */
min: gl.NEAREST,
wrap: gl.CLAMP_TO_EDGE,
src: bitmapData
};
@ -88,7 +91,7 @@ class BitmapSkin extends Skin {
/**
* @param {ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} bitmapData - bitmap data to inspect.
* @returns {[int,int]} the width and height of the bitmap data, in pixels.
* @returns {Array<int>} the width and height of the bitmap data, in pixels.
* @private
*/
static _getBitmapSize (bitmapData) {

View file

@ -9,7 +9,7 @@ const Skin = require('./Skin');
class Drawable {
/**
* An object which can be drawn by the renderer.
* TODO: double-buffer all rendering state (position, skin, effects, etc.)
* @todo double-buffer all rendering state (position, skin, effects, etc.)
* @param {!int} id - This Drawable's unique ID.
* @constructor
*/
@ -32,7 +32,7 @@ class Drawable {
/**
* The color to use in the silhouette draw mode.
* @type {number[]}
* @type {Array<number>}
*/
u_silhouetteColor: Drawable.color4fFromID(this._id)
};
@ -52,7 +52,7 @@ class Drawable {
this._visible = true;
this._effectBits = 0;
// TODO: move convex hull functionality, maybe bounds functionality overall, to Skin classes
/** @todo move convex hull functionality, maybe bounds functionality overall, to Skin classes */
this._convexHullPoints = null;
this._convexHullDirty = true;
@ -106,7 +106,7 @@ class Drawable {
}
/**
* @returns {[number,number]} the current scaling percentages applied to this Drawable. [100,100] is normal size.
* @returns {Array<number>} the current scaling percentages applied to this Drawable. [100,100] is normal size.
*/
get scale () {
return [this._scale[0], this._scale[1]];
@ -232,7 +232,7 @@ class Drawable {
/**
* Set the convex hull points for the Drawable.
* @param {Array.<Array.<number>>} points Convex hull points, as [[x, y], ...]
* @param {Array<Array<number>>} points Convex hull points, as [[x, y], ...]
*/
setConvexHullPoints (points) {
this._convexHullPoints = points;
@ -326,7 +326,7 @@ class Drawable {
* Calculate a color to represent the given ID number. At least one component of
* the resulting color will be non-zero if the ID is not RenderConstants.ID_NONE.
* @param {int} id The ID to convert.
* @returns {number[]} An array of [r,g,b,a], each component in the range [0,1].
* @returns {Array<number>} An array of [r,g,b,a], each component in the range [0,1].
*/
static color4fFromID (id) {
id -= RenderConstants.ID_NONE;

View file

@ -6,14 +6,17 @@ const Skin = require('./Skin');
/**
* Attributes to use when drawing with the pen
* @typedef {object} PenAttributes
* @typedef {object} PenSkin#PenAttributes
* @property {number} [diameter] - The size (diameter) of the pen.
* @property {number[]} [color4f] - The pen color as an array of [r,g,b,a], each component in the range [0,1].
* @property {Array<number>} [color4f] - The pen color as an array of [r,g,b,a], each component in the range [0,1].
*/
/**
* The pen attributes to use when unspecified.
* @type {PenAttributes}
* @type {PenSkin#PenAttributes}
* @memberof PenSkin
* @private
* @const
*/
const DefaultPenAttributes = {
color4f: [0, 0, 1, 1],
@ -26,11 +29,16 @@ class PenSkin extends Skin {
* Create a Skin which implements a Scratch pen layer.
* @param {int} id - The unique ID for this Skin.
* @param {RenderWebGL} renderer - The renderer which will use this Skin.
* @extends Skin
* @listens RenderWebGL#event:NativeSizeChanged
*/
constructor (id, renderer) {
super(id);
/** @type {RenderWebGL} */
/**
* @private
* @type {RenderWebGL}
*/
this._renderer = renderer;
/** @type {HTMLCanvasElement} */
@ -59,7 +67,7 @@ class PenSkin extends Skin {
}
/**
* @return {[number,number]} the "native" size, in texels, of this skin.
* @return {Array<number>} the "native" size, in texels, of this skin. [width, height]
*/
get size () {
return [this._canvas.width, this._canvas.height];
@ -143,7 +151,7 @@ class PenSkin extends Skin {
/**
* Set the size of the pen canvas.
* @param {[int,int]} canvasSize - the new width and height for the canvas.
* @param {Array<int>} canvasSize - the new width and height for the canvas.
* @private
*/
_setCanvasSize (canvasSize) {

View file

@ -1,10 +1,6 @@
/**
* @fileoverview
* A utility for creating and comparing axis-aligned rectangles.
*/
class Rectangle {
/**
* A utility for creating and comparing axis-aligned rectangles.
* Rectangles are always initialized to the "largest possible rectangle";
* use one of the init* methods below to set up a particular rectangle.
* @constructor
@ -32,7 +28,7 @@ class Rectangle {
/**
* Initialize a Rectangle to the minimum AABB around a set of points.
* @param {Array.<Array.<number>>} points Array of [x, y] points.
* @param {Array<Array<number>>} points Array of [x, y] points.
*/
initFromPointsAABB (points) {
this.left = Infinity;

View file

@ -1,3 +1,4 @@
/** @module RenderConstants */
const DEFAULT_SKIN = {
squirrel: 'https://cdn.assets.scratch.mit.edu/internalapi/asset/7e24c99c1b853e52f8e7f9004416fa34.png/get/',
bus: 'https://cdn.assets.scratch.mit.edu/internalapi/asset/66895930177178ea01d9e610917f8acf.png/get/',
@ -7,29 +8,40 @@ const DEFAULT_SKIN = {
/**
* Various constants meant for use throughout the renderer.
* @type {object}
* @enum
*/
module.exports = {
/**
* The ID value to use for "no item" or when an object has been disposed.
* @type {int}
* @const {int}
*/
ID_NONE: -1,
/**
* The URL to use as the default skin for a Drawable.
* TODO: Remove this in favor of falling back on a built-in skin.
* @type {string}
* @todo Remove this in favor of falling back on a built-in skin.
* @const {string}
*/
DEFAULT_SKIN: DEFAULT_SKIN,
/**
* Optimize for fewer than this number of Drawables sharing the same Skin.
* Going above this may cause middleware warnings or a performance penalty but should otherwise behave correctly.
* @const {int}
*/
SKIN_SHARE_SOFT_LIMIT: 300,
/**
* @enum {string}
*/
Events: {
/**
* NativeSizeChanged event
*
* @event RenderWebGL#event:NativeSizeChanged
* @type {object}
* @property {Array<int>} newSize - the new size of the renderer
*/
NativeSizeChanged: 'NativeSizeChanged'
}
};

View file

@ -12,15 +12,16 @@ const ShaderManager = require('./ShaderManager');
const SVGSkin = require('./SVGSkin');
/**
* @callback idFilterFunc
* @callback RenderWebGL#idFilterFunc
* @param {int} drawableID The ID to filter.
* @return {bool} True if the ID passes the filter, otherwise false.
*/
/**
* Maximum touch size for a picking check.
* TODO: Figure out a reasonable max size. Maybe this should be configurable?
* @type {int[]}
* @todo Figure out a reasonable max size. Maybe this should be configurable?
* @type {Array<int>}
* @memberof RenderWebGL
*/
const MAX_TOUCH_SIZE = [3, 3];
@ -28,7 +29,9 @@ const MAX_TOUCH_SIZE = [3, 3];
* "touching {color}?" or "{color} touching {color}?" tests will be true if the
* target is touching a color whose components are each within this tolerance of
* the corresponding component of the query color.
* @type {int} between 0 (exact matches only) and 255 (match anything).
* between 0 (exact matches only) and 255 (match anything).
* @type {int}
* @memberof RenderWebGL
*/
const TOLERANCE_TOUCHING_COLOR = 2;
@ -40,14 +43,15 @@ class RenderWebGL extends EventEmitter {
* The stage's "native" size will be calculated from the these coordinates.
* For example, the defaults result in a native size of 480x360.
* Queries such as "touching color?" will always execute at the native size.
* @see setStageSize
* @see resize
* @see RenderWebGL#setStageSize
* @see RenderWebGL#resize
* @param {canvas} canvas The canvas to draw onto.
* @param {int} [xLeft=-240] The x-coordinate of the left edge.
* @param {int} [xRight=240] The x-coordinate of the right edge.
* @param {int} [yBottom=-180] The y-coordinate of the bottom edge.
* @param {int} [yTop=180] The y-coordinate of the top edge.
* @constructor
* @listens RenderWebGL#event:NativeSizeChanged
*/
constructor (canvas, xLeft, xRight, yBottom, yTop) {
super();
@ -58,7 +62,7 @@ class RenderWebGL extends EventEmitter {
/** @type {Skin[]} */
this._allSkins = [];
/** @type {int[]} */
/** @type {Array<int>} */
this._drawList = [];
/** @type {WebGLRenderingContext} */
@ -76,6 +80,7 @@ class RenderWebGL extends EventEmitter {
/** @type {Object.<string,int>} */
this._skinUrlMap = {};
/** @type {ShaderManager} */
this._shaderManager = new ShaderManager(gl);
/** @type {HTMLCanvasElement} */
@ -90,7 +95,8 @@ class RenderWebGL extends EventEmitter {
this.resize(this._nativeSize[0], this._nativeSize[1]);
gl.disable(gl.DEPTH_TEST);
gl.enable(gl.BLEND); // TODO: disable when no partial transparency?
/** @todo disable when no partial transparency? */
gl.enable(gl.BLEND);
gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE);
}
@ -153,7 +159,7 @@ class RenderWebGL extends EventEmitter {
}
/**
* @return {[int,int]} the "native" size of the stage, which is used for pen, query renders, etc.
* @return {Array<int>} the "native" size of the stage, which is used for pen, query renders, etc.
*/
getNativeSize () {
return [this._nativeSize[0], this._nativeSize[1]];
@ -164,6 +170,7 @@ class RenderWebGL extends EventEmitter {
* @param {int} width - the new width to set.
* @param {int} height - the new height to set.
* @private
* @fires RenderWebGL#event:NativeSizeChanged
*/
_setNativeSize (width, height) {
this._nativeSize = [width, height];
@ -176,8 +183,8 @@ class RenderWebGL extends EventEmitter {
* Use `createBitmapSkin` or `createSVGSkin` instead.
* @param {!string} skinUrl The URL of the skin.
* @param {!int} [costumeResolution] Optional: resolution for the skin. Ignored unless creating a new Bitmap skin.
* @param {number[]=} rotationCenter Optional: rotation center of the skin. If not supplied, the center of the skin
* will be used.
* @param {?Array<number>} rotationCenter Optional: rotation center of the skin. If not supplied, the center of the
* skin will be used.
* @returns {!int} The ID of the Skin.
* @deprecated
*/
@ -238,7 +245,8 @@ class RenderWebGL extends EventEmitter {
* Create a new bitmap skin from a snapshot of the provided bitmap data.
* @param {ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} bitmapData - new contents for this skin.
* @param {!int} [costumeResolution=1] - The resolution to use for this bitmap.
* @param {number[]=} rotationCenter Optional: rotation center of the skin. If not supplied, the center of the skin
* @param {?Array<number>} rotationCenter Optional: rotation center of the skin. If not supplied, the center of the
* skin will be used
* @returns {!int} the ID for the new skin.
*/
createBitmapSkin (bitmapData, costumeResolution, rotationCenter) {
@ -252,7 +260,8 @@ class RenderWebGL extends EventEmitter {
/**
* Create a new SVG skin.
* @param {!string} svgData - new SVG to use.
* @param {number[]=} rotationCenter Optional: rotation center of the skin. If not supplied, the center of the skin
* @param {?Array<number>} rotationCenter Optional: rotation center of the skin. If not supplied, the center of the
* skin will be used
* @returns {!int} the ID for the new skin.
*/
createSVGSkin (svgData, rotationCenter) {
@ -398,7 +407,7 @@ class RenderWebGL extends EventEmitter {
/**
* Get the current skin (costume) size of a Drawable.
* @param {int} drawableID The ID of the Drawable to measure.
* @return {Array.<number>} Skin size, width and height.
* @return {Array<number>} Skin size, width and height.
*/
getSkinSize (drawableID) {
const drawable = this._allDrawables[drawableID];
@ -408,8 +417,8 @@ class RenderWebGL extends EventEmitter {
/**
* Check if a particular Drawable is touching a particular color.
* @param {int} drawableID The ID of the Drawable to check.
* @param {int[]} color3b Test if the Drawable is touching this color.
* @param {int[]} [mask3b] Optionally mask the check to this part of Drawable.
* @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.
* @returns {boolean} True iff the Drawable is touching the color.
*/
isTouchingColor (drawableID, color3b, mask3b) {
@ -496,7 +505,7 @@ class RenderWebGL extends EventEmitter {
/**
* Check if a particular Drawable is touching any in a set of Drawables.
* @param {int} drawableID The ID of the Drawable to check.
* @param {int[]} candidateIDs The Drawable IDs to check, otherwise all.
* @param {Array<int>} candidateIDs The Drawable IDs to check, otherwise all.
* @returns {boolean} True iff the Drawable is touching one of candidateIDs.
*/
isTouchingDrawables (drawableID, candidateIDs) {
@ -574,7 +583,7 @@ class RenderWebGL extends EventEmitter {
* @param {int} centerY The client y coordinate of the picking location.
* @param {int} touchWidth The client width of the touch event (optional).
* @param {int} touchHeight The client height of the touch event (optional).
* @param {int[]} candidateIDs The Drawable IDs to pick from, otherwise all.
* @param {Array<int>} candidateIDs The Drawable IDs to pick from, otherwise all.
* @returns {int} The ID of the topmost Drawable under the picking location, or
* RenderConstants.ID_NONE if there is no Drawable at that location.
*/
@ -735,7 +744,7 @@ class RenderWebGL extends EventEmitter {
_touchingBounds (drawableID) {
const drawable = this._allDrawables[drawableID];
// TODO: remove this once URL-based skin setting is removed.
/** @todo remove this once URL-based skin setting is removed. */
if (!drawable.skin || !drawable.skin.getTexture([100, 100])) return null;
const bounds = drawable.getFastBounds();
@ -758,9 +767,9 @@ class RenderWebGL extends EventEmitter {
* Filter a list of candidates for a touching query into only those that
* could possibly intersect the given bounds.
* @param {int} drawableID - ID for drawable of query.
* @param {Array.<int>} candidateIDs - Candidates for touching query.
* @param {Array<int>} candidateIDs - Candidates for touching query.
* @param {Rectangle} bounds - Bounds to limit candidates to.
* @return {?Array.<int>} Filtered candidateIDs, or null if none.
* @return {?Array<int>} Filtered candidateIDs, or null if none.
*/
_filterCandidatesTouching (drawableID, candidateIDs, bounds) {
// Filter candidates by rough bounding box intersection.
@ -788,11 +797,13 @@ class RenderWebGL extends EventEmitter {
updateDrawableProperties (drawableID, properties) {
const drawable = this._allDrawables[drawableID];
if (!drawable) {
// TODO: fix whatever's wrong in the VM which causes this, then add a warning or throw here.
// Right now this happens so much on some projects that a warning or exception here can hang the browser.
/**
* @todo fix whatever's wrong in the VM which causes this, then add a warning or throw here.
* Right now this happens so much on some projects that a warning or exception here can hang the browser.
*/
return;
}
// TODO: remove this after fully deprecating URL-based skin paths
/** @todo remove this after fully deprecating URL-based skin paths */
if ('skin' in properties) {
const {skin, costumeResolution, rotationCenter} = properties;
const skinId = this.createSkinFromURL(skin, costumeResolution, rotationCenter);
@ -949,7 +960,7 @@ class RenderWebGL extends EventEmitter {
this._pickBufferInfo = twgl.createFramebufferInfo(gl, attachments, MAX_TOUCH_SIZE[0], MAX_TOUCH_SIZE[1]);
}
// TODO: should we create this on demand to save memory?
/** @todo should we create this on demand to save memory? */
// A 480x360 32-bpp buffer is 675 KiB.
if (this._queryBufferInfo) {
twgl.resizeFramebufferInfo(gl, this._queryBufferInfo, attachments, width, height);
@ -959,8 +970,8 @@ class RenderWebGL extends EventEmitter {
}
/**
* Draw all Drawables, with the possible exception of
* @param {int[]} drawables The Drawable IDs to draw, possibly this._drawList.
* Draw a set of Drawables, by drawable ID
* @param {Array<int>} drawables The Drawable IDs to draw, possibly this._drawList.
* @param {ShaderManager.DRAW_MODE} drawMode Draw normally, silhouette, etc.
* @param {module:twgl/m4.Mat4} projection The projection matrix to use.
* @param {object} [opts] Options for drawing
@ -981,7 +992,7 @@ class RenderWebGL extends EventEmitter {
if (opts.filter && !opts.filter(drawableID)) continue;
const drawable = this._allDrawables[drawableID];
// TODO: check if drawable is inside the viewport before anything else
/** @todo check if drawable is inside the viewport before anything else */
// Hidden drawables (e.g., by a "hide" block) are never drawn.
if (!drawable.getVisible()) continue;
@ -1020,7 +1031,7 @@ class RenderWebGL extends EventEmitter {
* Read back the pixels and find all boundary points.
* Finally, apply a convex hull algorithm to simplify the set.
* @param {int} drawableID The Drawable IDs calculate convex hull for.
* @return {Array.<Array.<number>>} points Convex hull points, as [[x, y], ...]
* @return {Array<Array<number>>} points Convex hull points, as [[x, y], ...]
*/
_getConvexHullPointsForDrawable (drawableID) {
const drawable = this._allDrawables[drawableID];

View file

@ -8,6 +8,8 @@ class SVGSkin extends Skin {
* Create a new SVG skin.
* @param {!int} id - The ID for this Skin.
* @param {!RenderWebGL} renderer - The renderer which will use this skin.
* @constructor
* @extends Skin
*/
constructor (id, renderer) {
super(id);
@ -34,7 +36,7 @@ class SVGSkin extends Skin {
}
/**
* @return {[number,number]} the natural size, in Scratch units, of this skin.
* @return {Array<number>} the natural size, in Scratch units, of this skin.
*/
get size () {
return this._svgRenderer.size;
@ -51,20 +53,21 @@ class SVGSkin extends Skin {
}
/**
* @param {[number,number]} scale - The scaling factors to be used.
* @param {Array<number>} scale - The scaling factors to be used.
* @return {WebGLTexture} The GL texture representation of this skin when drawing at the given scale.
*/
// eslint-disable-next-line no-unused-vars
getTexture (scale) {
// TODO: re-render a scaled version if the requested scale is significantly larger than the current render
/** @todo re-render a scaled version if the requested scale is significantly larger than the current render */
return this._texture;
}
/**
* Set the contents of this skin to a snapshot of the provided SVG data.
* @param {string} svgData - new SVG to use.
* @param {number[]=} rotationCenter - Optional rotation center for the SVG. If not supplied, it will be
* @param {Array<number>} [rotationCenter] - Optional rotation center for the SVG. If not supplied, it will be
* calculated from the bounding box
* @fires Skin.event:WasAltered
*/
setSVG (svgData, rotationCenter) {
this._svgRenderer.fromString(svgData, () => {
@ -76,7 +79,7 @@ class SVGSkin extends Skin {
const textureOptions = {
auto: true,
mag: gl.NEAREST,
min: gl.NEAREST, // TODO: mipmaps, linear (except pixelate)
min: gl.NEAREST, /** @todo mipmaps, linear (except pixelate) */
wrap: gl.CLAMP_TO_EDGE,
src: this._svgRenderer.canvas
};

View file

@ -5,12 +5,16 @@ const fragmentShaderText = require('./shaders/sprite.frag');
class ShaderManager {
/**
* @param {WebGLRenderingContext} gl WebGL rendering context to create shaders for
* @constructor
*/
constructor (gl) {
this._gl = gl;
/**
* The cache of all shaders compiled so far, filled on demand.
* @type {Object.<ShaderManager.DRAW_MODE, Array.<ProgramInfo>>}
* @type {Object<ShaderManager.DRAW_MODE, Array<ProgramInfo>>}
* @private
*/
this._shaderCache = {};
@ -69,50 +73,60 @@ class ShaderManager {
}
/**
* Mapping of each effect name to info about that effect.
* The info includes:
* - The bit in 'effectBits' representing the effect.
* - A conversion function which takes a Scratch value (generally in the range
* @typedef {object} ShaderManager.Effect
* @prop {int} mask - The bit in 'effectBits' representing the effect.
* @prop {function} converter - A conversion function which takes a Scratch value (generally in the range
* 0..100 or -100..100) and maps it to a value useful to the shader. This
* mapping may not be reversible.
* - `shapeChanges`, whether the effect could change the drawn shape.
* @type {Object.<string,Object.<string,*>>}
* @prop {boolean} shapeChanges - Whether the effect could change the drawn shape.
*/
/**
* Mapping of each effect name to info about that effect.
* @enum {ShaderManager.Effect}
*/
ShaderManager.EFFECT_INFO = {
/** Color effect */
color: {
mask: 1 << 0,
converter: x => (x / 200) % 1,
shapeChanges: false
},
/** Fisheye effect */
fisheye: {
mask: 1 << 1,
converter: x => Math.max(0, (x + 100) / 100),
shapeChanges: true
},
/** Whirl effect */
whirl: {
mask: 1 << 2,
converter: x => -x * Math.PI / 180,
shapeChanges: true
},
/** Pixelate effect */
pixelate: {
mask: 1 << 3,
converter: x => Math.abs(x) / 10,
shapeChanges: true
},
/** Mosaic effect */
mosaic: {
mask: 1 << 4,
converter: x => {
x = Math.round((Math.abs(x) + 10) / 10);
// TODO: cap by Math.min(srcWidth, srcHeight)
/** @todo cap by Math.min(srcWidth, srcHeight) */
return Math.max(1, Math.min(x, 512));
},
shapeChanges: true
},
/** Brightness effect */
brightness: {
mask: 1 << 5,
converter: x => Math.max(-100, Math.min(x, 100)) / 100,
shapeChanges: false
},
/** Ghost effect */
ghost: {
mask: 1 << 6,
converter: x => 1 - (Math.max(0, Math.min(x, 100)) / 100),

View file

@ -8,6 +8,7 @@ class Skin extends EventEmitter {
/**
* Create a Skin, which stores and/or generates textures for use in rendering.
* @param {int} id - The unique ID for this Skin.
* @constructor
*/
constructor (id) {
super();
@ -27,7 +28,7 @@ class Skin extends EventEmitter {
this._uniforms = {
/**
* The nominal (not necessarily current) size of the current skin.
* @type {number[]}
* @type {Array<number>}
*/
u_skinSize: [0, 0],
@ -64,7 +65,7 @@ class Skin extends EventEmitter {
/**
* @abstract
* @return {[number,number]} the "native" size, in texels, of this skin.
* @return {Array<number>} the "native" size, in texels, of this skin.
*/
get size () {
return [0, 0];
@ -74,6 +75,7 @@ class Skin extends EventEmitter {
* Set the origin, in object space, about which this Skin should rotate.
* @param {number} x - The x coordinate of the new rotation center.
* @param {number} y - The y coordinate of the new rotation center.
* @fires Skin.event:WasAltered
*/
setRotationCenter (x, y) {
if (x !== this._rotationCenter[0] || y !== this._rotationCenter[1]) {
@ -85,7 +87,7 @@ class Skin extends EventEmitter {
/**
* Get the center of the current bounding box
* @return {[number,number]} the center of the current bounding box
* @return {Array<number>} the center of the current bounding box
*/
calculateRotationCenter () {
return [this.size[0] / 2, this.size[1] / 2];
@ -93,7 +95,7 @@ class Skin extends EventEmitter {
/**
* @abstract
* @param {[number,number]} scale - The scaling factors to be used.
* @param {Array<number>} scale - The scaling factors to be used.
* @return {WebGLTexture} The GL texture representation of this skin when drawing at the given size.
*/
// eslint-disable-next-line no-unused-vars
@ -103,7 +105,7 @@ class Skin extends EventEmitter {
/**
* Update and returns the uniforms for this skin.
* @param {[number,number]} scale - The scaling factors to be used.
* @param {Array<number>} scale - The scaling factors to be used.
* @returns {object.<string, *>} the shader uniforms to be used when rendering with this Skin.
*/
getUniforms (scale) {
@ -115,11 +117,12 @@ class Skin extends EventEmitter {
/**
* These are the events which can be emitted by instances of this class.
* @type {object.<string,string>}
* @enum {string}
*/
Skin.Events = {
/**
* Emitted when anything about the Skin has been altered, such as the appearance or rotation center.
* @event Skin.event:WasAltered
*/
WasAltered: 'WasAltered'
};

View file

@ -52,7 +52,7 @@ class SvgRenderer {
* This will be parsed and transformed, and finally drawn.
* When drawing is finished, the `onFinish` callback is called.
* @param {string} svgString String of SVG data to draw in quirks-mode.
* @param {Function=} onFinish Optional callback for when drawing finished.
* @param {Function} [onFinish] Optional callback for when drawing finished.
*/
fromString (svgString, onFinish) {
// Store the callback for later.
@ -74,14 +74,14 @@ class SvgRenderer {
}
/**
* @return {[number,number]} the natural size, in Scratch units, of this SVG.
* @return {Array<number>} the natural size, in Scratch units, of this SVG.
*/
get size () {
return [this._measurements.width, this._measurements.height];
}
/**
* @return {[number,number]} the offset (upper left corner) of the SVG's view box.
* @return {Array<number>} the offset (upper left corner) of the SVG's view box.
*/
get viewOffset () {
return [this._measurements.x, this._measurements.y];