From 3c6511d94e46a183ed05a39ac9f26cc3a5f07bf8 Mon Sep 17 00:00:00 2001 From: Ray Schamp Date: Sun, 19 Feb 2017 23:57:55 -0500 Subject: [PATCH] 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). --- .gitignore | 1 + .jsdoc.json | 20 +++++++++ package.json | 15 ++++--- src/BitmapSkin.js | 15 ++++--- src/Drawable.js | 12 ++--- src/PenSkin.js | 20 ++++++--- src/Rectangle.js | 8 +--- src/RenderConstants.js | 20 +++++++-- src/RenderWebGL.js | 69 +++++++++++++++++------------ src/SVGSkin.js | 13 +++--- src/ShaderManager.js | 30 +++++++++---- src/Skin.js | 15 ++++--- src/svg-quirks-mode/svg-renderer.js | 6 +-- 13 files changed, 159 insertions(+), 85 deletions(-) create mode 100644 .jsdoc.json diff --git a/.gitignore b/.gitignore index c58b010..5519ad3 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ npm-* /dist /playground/scratch-render.js /playground/scratch-render.js.map +/playground/docs diff --git a/.jsdoc.json b/.jsdoc.json new file mode 100644 index 0000000..f4d8b9f --- /dev/null +++ b/.jsdoc.json @@ -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" + } +} diff --git a/package.json b/package.json index 1c11426..58fa340 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/BitmapSkin.js b/src/BitmapSkin.js index 0deb8af..df304dd 100644 --- a/src/BitmapSkin.js +++ b/src/BitmapSkin.js @@ -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} */ 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} 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} 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} [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} the width and height of the bitmap data, in pixels. * @private */ static _getBitmapSize (bitmapData) { diff --git a/src/Drawable.js b/src/Drawable.js index 71baa1d..a98d0d3 100644 --- a/src/Drawable.js +++ b/src/Drawable.js @@ -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} */ 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} 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.>} points Convex hull points, as [[x, y], ...] + * @param {Array>} 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} An array of [r,g,b,a], each component in the range [0,1]. */ static color4fFromID (id) { id -= RenderConstants.ID_NONE; diff --git a/src/PenSkin.js b/src/PenSkin.js index 89b09bc..7de5246 100644 --- a/src/PenSkin.js +++ b/src/PenSkin.js @@ -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} [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} 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} canvasSize - the new width and height for the canvas. * @private */ _setCanvasSize (canvasSize) { diff --git a/src/Rectangle.js b/src/Rectangle.js index a6402a2..2d241b8 100644 --- a/src/Rectangle.js +++ b/src/Rectangle.js @@ -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.>} points Array of [x, y] points. + * @param {Array>} points Array of [x, y] points. */ initFromPointsAABB (points) { this.left = Infinity; diff --git a/src/RenderConstants.js b/src/RenderConstants.js index 877ecc7..12bdfd0 100644 --- a/src/RenderConstants.js +++ b/src/RenderConstants.js @@ -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} newSize - the new size of the renderer + */ NativeSizeChanged: 'NativeSizeChanged' } }; diff --git a/src/RenderWebGL.js b/src/RenderWebGL.js index 02d664e..f1ce507 100644 --- a/src/RenderWebGL.js +++ b/src/RenderWebGL.js @@ -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} + * @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} */ this._drawList = []; /** @type {WebGLRenderingContext} */ @@ -76,6 +80,7 @@ class RenderWebGL extends EventEmitter { /** @type {Object.} */ 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} 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} 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} 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} 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.} Skin size, width and height. + * @return {Array} 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} color3b Test if the Drawable is touching this color. + * @param {Array} [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} 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} 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.} candidateIDs - Candidates for touching query. + * @param {Array} candidateIDs - Candidates for touching query. * @param {Rectangle} bounds - Bounds to limit candidates to. - * @return {?Array.} Filtered candidateIDs, or null if none. + * @return {?Array} 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} 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.>} points Convex hull points, as [[x, y], ...] + * @return {Array>} points Convex hull points, as [[x, y], ...] */ _getConvexHullPointsForDrawable (drawableID) { const drawable = this._allDrawables[drawableID]; diff --git a/src/SVGSkin.js b/src/SVGSkin.js index 86a3c1c..e849bb1 100644 --- a/src/SVGSkin.js +++ b/src/SVGSkin.js @@ -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} 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} 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} [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 }; diff --git a/src/ShaderManager.js b/src/ShaderManager.js index 0c5d221..fb02341 100644 --- a/src/ShaderManager.js +++ b/src/ShaderManager.js @@ -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.>} + * @type {Object>} * @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.>} + * @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), diff --git a/src/Skin.js b/src/Skin.js index 90d7de9..d8ae569 100644 --- a/src/Skin.js +++ b/src/Skin.js @@ -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} */ 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} 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} 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} 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} scale - The scaling factors to be used. * @returns {object.} 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.} + * @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' }; diff --git a/src/svg-quirks-mode/svg-renderer.js b/src/svg-quirks-mode/svg-renderer.js index 6c5ff4f..2d7810d 100644 --- a/src/svg-quirks-mode/svg-renderer.js +++ b/src/svg-quirks-mode/svg-renderer.js @@ -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} 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} the offset (upper left corner) of the SVG's view box. */ get viewOffset () { return [this._measurements.x, this._measurements.y];