/*! p5.p5.Math.js v0.5.11 July 21, 2017 */ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.p5 = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o
* Note that drawing a full circle (ex: 0 to TWO_PI) will appear blank * because 0 and TWO_PI are the same position on the unit circle. The * best way to handle this is by using the ellipse() function instead * to create a closed ellipse, and to use the arc() function * only to draw parts of an ellipse. * * @method arc * @param {Number} a x-coordinate of the arc's ellipse * @param {Number} b y-coordinate of the arc's ellipse * @param {Number} c width of the arc's ellipse by default * @param {Number} d height of the arc's ellipse by default * @param {Number} start angle to start the arc, specified in radians * @param {Number} stop angle to stop the arc, specified in radians * @param {Constant} [mode] optional parameter to determine the way of drawing * the arc. either CHORD or PIE * @chainable * @example *
* * arc(50, 55, 50, 50, 0, HALF_PI); * noFill(); * arc(50, 55, 60, 60, HALF_PI, PI); * arc(50, 55, 70, 70, PI, PI+QUARTER_PI); * arc(50, 55, 80, 80, PI+QUARTER_PI, TWO_PI); * *
* *
* * arc(50, 50, 80, 80, 0, PI+QUARTER_PI, OPEN); * *
* *
* * arc(50, 50, 80, 80, 0, PI+QUARTER_PI, CHORD); * *
* *
* * arc(50, 50, 80, 80, 0, PI+QUARTER_PI, PIE); * *
* * @alt *shattered outline of an ellipse with a quarter of a white circle bottom-right. *white ellipse with black outline with top right missing. *white ellipse with top right missing with black outline around shape. *white ellipse with top right quarter missing with black outline around the shape. * */ p5.prototype.arc = function(x, y, w, h, start, stop, mode) { var args = new Array(arguments.length); for (var i = 0; i < args.length; ++i) { args[i] = arguments[i]; } if (!this._renderer._doStroke && !this._renderer._doFill) { return this; } if (this._angleMode === constants.DEGREES) { start = this.radians(start); stop = this.radians(stop); } // Make all angles positive... while (start < 0) { start += constants.TWO_PI; } while (stop < 0) { stop += constants.TWO_PI; } // ...and confine them to the interval [0,TWO_PI). start %= constants.TWO_PI; stop %= constants.TWO_PI; // account for full circle if (stop === start) { stop += constants.TWO_PI; } // Adjust angles to counter linear scaling. if (start <= constants.HALF_PI) { start = Math.atan(w / h * Math.tan(start)); } else if (start > constants.HALF_PI && start <= 3 * constants.HALF_PI) { start = Math.atan(w / h * Math.tan(start)) + constants.PI; } else { start = Math.atan(w / h * Math.tan(start)) + constants.TWO_PI; } if (stop <= constants.HALF_PI) { stop = Math.atan(w / h * Math.tan(stop)); } else if (stop > constants.HALF_PI && stop <= 3 * constants.HALF_PI) { stop = Math.atan(w / h * Math.tan(stop)) + constants.PI; } else { stop = Math.atan(w / h * Math.tan(stop)) + constants.TWO_PI; } // Exceed the interval if necessary in order to preserve the size and // orientation of the arc. if (start > stop) { stop += constants.TWO_PI; } // p5 supports negative width and heights for ellipses w = Math.abs(w); h = Math.abs(h); this._renderer.arc(x, y, w, h, start, stop, mode); return this; }; /** * Draws an ellipse (oval) to the screen. An ellipse with equal width and * height is a circle. By default, the first two parameters set the location, * and the third and fourth parameters set the shape's width and height. If * no height is specified, the value of width is used for both the width and * height. If a negative height or width is specified, the absolute value is taken. * The origin may be changed with the ellipseMode() function. * * @method ellipse * @param {Number} x x-coordinate of the ellipse. * @param {Number} y y-coordinate of the ellipse. * @param {Number} w width of the ellipse. * @param {Number} [h] height of the ellipse. * @chainable * @example *
* * ellipse(56, 46, 55, 55); * *
* * @alt *white ellipse with black outline in middle-right of canvas that is 55x55. * */ p5.prototype.ellipse = function() { var args = new Array(arguments.length); for (var i = 0; i < args.length; ++i) { args[i] = arguments[i]; } // Duplicate 3rd argument if only 3 given. if (args.length === 3) { args.push(args[2]); } // p5 supports negative width and heights for rects if (args[2] < 0){args[2] = Math.abs(args[2]);} if (args[3] < 0){args[3] = Math.abs(args[3]);} if (!this._renderer._doStroke && !this._renderer._doFill) { return this; } var vals = canvas.modeAdjust( args[0], args[1], args[2], args[3], this._renderer._ellipseMode); args[0] = vals.x; args[1] = vals.y; args[2] = vals.w; args[3] = vals.h; this._renderer.ellipse(args); return this; }; /** * Draws a line (a direct path between two points) to the screen. The version * of line() with four parameters draws the line in 2D. To color a line, use * the stroke() function. A line cannot be filled, therefore the fill() * function will not affect the color of a line. 2D lines are drawn with a * width of one pixel by default, but this can be changed with the * strokeWeight() function. * * @method line * @param {Number} x1 the x-coordinate of the first point * @param {Number} y1 the y-coordinate of the first point * @param {Number} x2 the x-coordinate of the second point * @param {Number} y2 the y-coordinate of the second point * @chainable * @example *
* * line(30, 20, 85, 75); * *
* *
* * line(30, 20, 85, 20); * stroke(126); * line(85, 20, 85, 75); * stroke(255); * line(85, 75, 30, 75); * *
* * @alt *line 78 pixels long running from mid-top to bottom-right of canvas. *3 lines of various stroke sizes. Form top, bottom and right sides of a square. * */ ////commented out original // p5.prototype.line = function(x1, y1, x2, y2) { // if (!this._renderer._doStroke) { // return this; // } // if(this._renderer.isP3D){ // } else { // this._renderer.line(x1, y1, x2, y2); // } // }; p5.prototype.line = function() { if (!this._renderer._doStroke) { return this; } var args = new Array(arguments.length); for (var i = 0; i < args.length; ++i) { args[i] = arguments[i]; } //check whether we should draw a 3d line or 2d if(this._renderer.isP3D){ this._renderer.line( args[0], args[1], args[2], args[3], args[4], args[5]); } else { this._renderer.line( args[0], args[1], args[2], args[3]); } return this; }; /** * Draws a point, a coordinate in space at the dimension of one pixel. * The first parameter is the horizontal value for the point, the second * value is the vertical value for the point. The color of the point is * determined by the current stroke. * * @method point * @param {Number} x the x-coordinate * @param {Number} y the y-coordinate * @chainable * @example *
* * point(30, 20); * point(85, 20); * point(85, 75); * point(30, 75); * *
* * @alt *4 points centered in the middle-right of the canvas. * */ p5.prototype.point = function() { if (!this._renderer._doStroke) { return this; } var args = new Array(arguments.length); for (var i = 0; i < args.length; ++i) { args[i] = arguments[i]; } //check whether we should draw a 3d line or 2d if(this._renderer.isP3D){ this._renderer.point( args[0], args[1], args[2] ); } else { this._renderer.point( args[0], args[1] ); } return this; }; /** * Draw a quad. A quad is a quadrilateral, a four sided polygon. It is * similar to a rectangle, but the angles between its edges are not * constrained to ninety degrees. The first pair of parameters (x1,y1) * sets the first vertex and the subsequent pairs should proceed * clockwise or counter-clockwise around the defined shape. * * @method quad * @param {Number} x1 the x-coordinate of the first point * @param {Number} y1 the y-coordinate of the first point * @param {Number} x2 the x-coordinate of the second point * @param {Number} y2 the y-coordinate of the second point * @param {Number} x3 the x-coordinate of the third point * @param {Number} y3 the y-coordinate of the third point * @param {Number} x4 the x-coordinate of the fourth point * @param {Number} y4 the y-coordinate of the fourth point * @chainable * @example *
* * quad(38, 31, 86, 20, 69, 63, 30, 76); * *
* * @alt *irregular white quadrilateral shape with black outline mid-right of canvas. * */ /** * @method quad * @param {Number} x1 * @param {Number} y1 * @param {Number} x2 * @param {Number} y2 * @param {Number} x3 * @param {Number} y3 * @param {Number} x4 * @param {Number} y4 * @chainable */ p5.prototype.quad = function() { if (!this._renderer._doStroke && !this._renderer._doFill) { return this; } var args = new Array(arguments.length); for (var i = 0; i < args.length; ++i) { args[i] = arguments[i]; } if(this._renderer.isP3D){ this._renderer.quad( args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11] ); } else { this._renderer.quad( args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7] ); } return this; }; /** * Draws a rectangle to the screen. A rectangle is a four-sided shape with * every angle at ninety degrees. By default, the first two parameters set * the location of the upper-left corner, the third sets the width, and the * fourth sets the height. The way these parameters are interpreted, however, * may be changed with the rectMode() function. *

* The fifth, sixth, seventh and eighth parameters, if specified, * determine corner radius for the top-right, top-left, lower-right and * lower-left corners, respectively. An omitted corner radius parameter is set * to the value of the previously specified radius value in the parameter list. * * @method rect * @param {Number} x x-coordinate of the rectangle. * @param {Number} y y-coordinate of the rectangle. * @param {Number} w width of the rectangle. * @param {Number} h height of the rectangle. * @param {Number} [tl] optional radius of top-left corner. * @param {Number} [tr] optional radius of top-right corner. * @param {Number} [br] optional radius of bottom-right corner. * @param {Number} [bl] optional radius of bottom-left corner. * @return {p5} the p5 object. * @example *
* * // Draw a rectangle at location (30, 20) with a width and height of 55. * rect(30, 20, 55, 55); * *
* *
* * // Draw a rectangle with rounded corners, each having a radius of 20. * rect(30, 20, 55, 55, 20); * *
* *
* * // Draw a rectangle with rounded corners having the following radii: * // top-left = 20, top-right = 15, bottom-right = 10, bottom-left = 5. * rect(30, 20, 55, 55, 20, 15, 10, 5); * *
* * @alt * 55x55 white rect with black outline in mid-right of canvas. * 55x55 white rect with black outline and rounded edges in mid-right of canvas. * 55x55 white rect with black outline and rounded edges of different radii. */ /** * @method rect * @param {Number} x * @param {Number} y * @param {Number} w * @param {Number} h * @param {Number} [detailX] * @param {Number} [detailY] * @chainable */ p5.prototype.rect = function () { var args = new Array(arguments.length); for (var i = 0; i < args.length; ++i) { args[i] = arguments[i]; } if (!this._renderer._doStroke && !this._renderer._doFill) { return this; } var vals = canvas.modeAdjust( args[0], args[1], args[2], args[3], this._renderer._rectMode); args[0] = vals.x; args[1] = vals.y; args[2] = vals.w; args[3] = vals.h; this._renderer.rect(args); return this; }; /** * A triangle is a plane created by connecting three points. The first two * arguments specify the first point, the middle two arguments specify the * second point, and the last two arguments specify the third point. * * @method triangle * @param {Number} x1 x-coordinate of the first point * @param {Number} y1 y-coordinate of the first point * @param {Number} x2 x-coordinate of the second point * @param {Number} y2 y-coordinate of the second point * @param {Number} x3 x-coordinate of the third point * @param {Number} y3 y-coordinate of the third point * @chainable * @example *
* * triangle(30, 75, 58, 20, 86, 75); * *
* *@alt * white triangle with black outline in mid-right of canvas. * */ p5.prototype.triangle = function() { if (!this._renderer._doStroke && !this._renderer._doFill) { return this; } var args = new Array(arguments.length); for (var i = 0; i < args.length; ++i) { args[i] = arguments[i]; } this._renderer.triangle(args); return this; }; module.exports = p5; },{"./canvas":3,"./constants":4,"./core":5,"./error_helpers":8}],2:[function(_dereq_,module,exports){ /** * @module Shape * @submodule Attributes * @for p5 * @requires core * @requires constants */ 'use strict'; var p5 = _dereq_('./core'); var constants = _dereq_('./constants'); /** * Modifies the location from which ellipses are drawn by changing the way * in which parameters given to ellipse() are interpreted. *

* The default mode is ellipseMode(CENTER), which interprets the first two * parameters of ellipse() as the shape's center point, while the third and * fourth parameters are its width and height. *

* ellipseMode(RADIUS) also uses the first two parameters of ellipse() as * the shape's center point, but uses the third and fourth parameters to * specify half of the shapes's width and height. *

* ellipseMode(CORNER) interprets the first two parameters of ellipse() as * the upper-left corner of the shape, while the third and fourth parameters * are its width and height. *

* ellipseMode(CORNERS) interprets the first two parameters of ellipse() as * the location of one corner of the ellipse's bounding box, and the third * and fourth parameters as the location of the opposite corner. *

* The parameter must be written in ALL CAPS because Javascript is a * case-sensitive language. * * @method ellipseMode * @param {Constant} mode either CENTER, RADIUS, CORNER, or CORNERS * @chainable * @example *
* * ellipseMode(RADIUS); // Set ellipseMode to RADIUS * fill(255); // Set fill to white * ellipse(50, 50, 30, 30); // Draw white ellipse using RADIUS mode * * ellipseMode(CENTER); // Set ellipseMode to CENTER * fill(100); // Set fill to gray * ellipse(50, 50, 30, 30); // Draw gray ellipse using CENTER mode * *
* *
* * ellipseMode(CORNER); // Set ellipseMode is CORNER * fill(255); // Set fill to white * ellipse(25, 25, 50, 50); // Draw white ellipse using CORNER mode * * ellipseMode(CORNERS); // Set ellipseMode to CORNERS * fill(100); // Set fill to gray * ellipse(25, 25, 50, 50); // Draw gray ellipse using CORNERS mode * *
* * @alt * 60x60 white ellipse and 30x30 grey ellipse with black outlines at center. * 60x60 white ellipse @center and 30x30 grey ellipse top-right, black outlines. * */ p5.prototype.ellipseMode = function(m) { if (m === constants.CORNER || m === constants.CORNERS || m === constants.RADIUS || m === constants.CENTER) { this._renderer._ellipseMode = m; } return this; }; /** * Draws all geometry with jagged (aliased) edges. Note that smooth() is * active by default, so it is necessary to call noSmooth() to disable * smoothing of geometry, images, and fonts. * * @method noSmooth * @chainable * @example *
* * background(0); * noStroke(); * smooth(); * ellipse(30, 48, 36, 36); * noSmooth(); * ellipse(70, 48, 36, 36); * *
* * @alt * 2 pixelated 36x36 white ellipses to left & right of center, black background * */ p5.prototype.noSmooth = function() { this._renderer.noSmooth(); return this; }; /** * Modifies the location from which rectangles are drawn by changing the way * in which parameters given to rect() are interpreted. *

* The default mode is rectMode(CORNER), which interprets the first two * parameters of rect() as the upper-left corner of the shape, while the * third and fourth parameters are its width and height. *

* rectMode(CORNERS) interprets the first two parameters of rect() as the * location of one corner, and the third and fourth parameters as the * location of the opposite corner. *

* rectMode(CENTER) interprets the first two parameters of rect() as the * shape's center point, while the third and fourth parameters are its * width and height. *

* rectMode(RADIUS) also uses the first two parameters of rect() as the * shape's center point, but uses the third and fourth parameters to specify * half of the shapes's width and height. *

* The parameter must be written in ALL CAPS because Javascript is a * case-sensitive language. * * @method rectMode * @param {Constant} mode either CORNER, CORNERS, CENTER, or RADIUS * @chainable * @example *
* * rectMode(CORNER); // Default rectMode is CORNER * fill(255); // Set fill to white * rect(25, 25, 50, 50); // Draw white rect using CORNER mode * * rectMode(CORNERS); // Set rectMode to CORNERS * fill(100); // Set fill to gray * rect(25, 25, 50, 50); // Draw gray rect using CORNERS mode * *
* *
* * rectMode(RADIUS); // Set rectMode to RADIUS * fill(255); // Set fill to white * rect(50, 50, 30, 30); // Draw white rect using RADIUS mode * * rectMode(CENTER); // Set rectMode to CENTER * fill(100); // Set fill to gray * rect(50, 50, 30, 30); // Draw gray rect using CENTER mode * *
* * @alt * 50x50 white rect at center and 25x25 grey rect in the top left of the other. * 50x50 white rect at center and 25x25 grey rect in the center of the other. * */ p5.prototype.rectMode = function(m) { if (m === constants.CORNER || m === constants.CORNERS || m === constants.RADIUS || m === constants.CENTER) { this._renderer._rectMode = m; } return this; }; /** * Draws all geometry with smooth (anti-aliased) edges. smooth() will also * improve image quality of resized images. Note that smooth() is active by * default; noSmooth() can be used to disable smoothing of geometry, * images, and fonts. * * @method smooth * @chainable * @example *
* * background(0); * noStroke(); * smooth(); * ellipse(30, 48, 36, 36); * noSmooth(); * ellipse(70, 48, 36, 36); * *
* * @alt * 2 pixelated 36x36 white ellipses one left one right of center. On black. * */ p5.prototype.smooth = function() { this._renderer.smooth(); return this; }; /** * Sets the style for rendering line endings. These ends are either squared, * extended, or rounded, each of which specified with the corresponding * parameters: SQUARE, PROJECT, and ROUND. The default cap is ROUND. * * @method strokeCap * @param {Constant} cap either SQUARE, PROJECT, or ROUND * @chainable * @example *
* * strokeWeight(12.0); * strokeCap(ROUND); * line(20, 30, 80, 30); * strokeCap(SQUARE); * line(20, 50, 80, 50); * strokeCap(PROJECT); * line(20, 70, 80, 70); * *
* * @alt * 3 lines. Top line: rounded ends, mid: squared, bottom:longer squared ends. * */ p5.prototype.strokeCap = function(cap) { if (cap === constants.ROUND || cap === constants.SQUARE || cap === constants.PROJECT) { this._renderer.strokeCap(cap); } return this; }; /** * Sets the style of the joints which connect line segments. These joints * are either mitered, beveled, or rounded and specified with the * corresponding parameters MITER, BEVEL, and ROUND. The default joint is * MITER. * * @method strokeJoin * @param {Constant} join either MITER, BEVEL, ROUND * @chainable * @example *
* * noFill(); * strokeWeight(10.0); * strokeJoin(MITER); * beginShape(); * vertex(35, 20); * vertex(65, 50); * vertex(35, 80); * endShape(); * *
* *
* * noFill(); * strokeWeight(10.0); * strokeJoin(BEVEL); * beginShape(); * vertex(35, 20); * vertex(65, 50); * vertex(35, 80); * endShape(); * *
* *
* * noFill(); * strokeWeight(10.0); * strokeJoin(ROUND); * beginShape(); * vertex(35, 20); * vertex(65, 50); * vertex(35, 80); * endShape(); * *
* * @alt * Right-facing arrowhead shape with pointed tip in center of canvas. * Right-facing arrowhead shape with flat tip in center of canvas. * Right-facing arrowhead shape with rounded tip in center of canvas. * */ p5.prototype.strokeJoin = function(join) { if (join === constants.ROUND || join === constants.BEVEL || join === constants.MITER) { this._renderer.strokeJoin(join); } return this; }; /** * Sets the width of the stroke used for lines, points, and the border * around shapes. All widths are set in units of pixels. * * @method strokeWeight * @param {Number} weight the weight (in pixels) of the stroke * @return {p5} the p5 object * @example *
* * strokeWeight(1); // Default * line(20, 20, 80, 20); * strokeWeight(4); // Thicker * line(20, 40, 80, 40); * strokeWeight(10); // Beastly * line(20, 70, 80, 70); * *
* * @alt * 3 horizontal black lines. Top line: thin, mid: medium, bottom:thick. * */ p5.prototype.strokeWeight = function(w) { this._renderer.strokeWeight(w); return this; }; module.exports = p5; },{"./constants":4,"./core":5}],3:[function(_dereq_,module,exports){ /** * @requires constants */ var constants = _dereq_('./constants'); module.exports = { modeAdjust: function(a, b, c, d, mode) { if (mode === constants.CORNER) { return { x: a, y: b, w: c, h: d }; } else if (mode === constants.CORNERS) { return { x: a, y: b, w: c-a, h: d-b }; } else if (mode === constants.RADIUS) { return { x: a-c, y: b-d, w: 2*c, h: 2*d }; } else if (mode === constants.CENTER) { return { x: a-c*0.5, y: b-d*0.5, w: c, h: d }; } }, arcModeAdjust: function(a, b, c, d, mode) { if (mode === constants.CORNER) { return { x: a+c*0.5, y: b+d*0.5, w: c, h: d }; } else if (mode === constants.CORNERS) { return { x: a, y: b, w: c+a, h: d+b }; } else if (mode === constants.RADIUS) { return { x: a, y: b, w: 2*c, h: 2*d }; } else if (mode === constants.CENTER) { return { x: a, y: b, w: c, h: d }; } } }; },{"./constants":4}],4:[function(_dereq_,module,exports){ /** * @module Constants * @submodule Constants * @for p5 */ var PI = Math.PI; module.exports = { // GRAPHICS RENDERER /** * @property {String} P2D * @final */ P2D: 'p2d', /** * @property {String} WEBGL * @final */ WEBGL: 'webgl', // ENVIRONMENT ARROW: 'default', CROSS: 'crosshair', HAND: 'pointer', MOVE: 'move', TEXT: 'text', WAIT: 'wait', // TRIGONOMETRY /** * HALF_PI is a mathematical constant with the value * 1.57079632679489661923. It is half the ratio of the * circumference of a circle to its diameter. It is useful in * combination with the trigonometric functions sin() and cos(). * * @property {Number} HALF_PI * @final * * @example *
* arc(50, 50, 80, 80, 0, HALF_PI); *
* * @alt * 80x80 white quarter-circle with curve toward bottom right of canvas. * */ HALF_PI: PI / 2, /** * PI is a mathematical constant with the value * 3.14159265358979323846. It is the ratio of the circumference * of a circle to its diameter. It is useful in combination with * the trigonometric functions sin() and cos(). * * @property {Number} PI * @final * * @example *
* arc(50, 50, 80, 80, 0, PI); *
* * @alt * white half-circle with curve toward bottom of canvas. * */ PI: PI, /** * QUARTER_PI is a mathematical constant with the value 0.7853982. * It is one quarter the ratio of the circumference of a circle to * its diameter. It is useful in combination with the trigonometric * functions sin() and cos(). * * @property {Number} QUARTER_PI * @final * * @example *
* arc(50, 50, 80, 80, 0, QUARTER_PI); *
* * @alt * white eighth-circle rotated about 40 degrees with curve bottom right canvas. * */ QUARTER_PI: PI / 4, /** * TAU is an alias for TWO_PI, a mathematical constant with the * value 6.28318530717958647693. It is twice the ratio of the * circumference of a circle to its diameter. It is useful in * combination with the trigonometric functions sin() and cos(). * * @property {Number} TAU * @final * * @example *
* arc(50, 50, 80, 80, 0, TAU); *
* * @alt * 80x80 white ellipse shape in center of canvas. * */ TAU: PI * 2, /** * TWO_PI is a mathematical constant with the value * 6.28318530717958647693. It is twice the ratio of the * circumference of a circle to its diameter. It is useful in * combination with the trigonometric functions sin() and cos(). * * @property {Number} TWO_PI * @final * * @example *
* arc(50, 50, 80, 80, 0, TWO_PI); *
* * @alt * 80x80 white ellipse shape in center of canvas. * */ TWO_PI: PI * 2, /** * @property {String} DEGREES * @final */ DEGREES: 'degrees', /** * @property {String} RADIANS * @final */ RADIANS: 'radians', DEG_TO_RAD: PI / 180.0, RAD_TO_DEG: 180.0 / PI, // SHAPE /** * @property {String} CORNER * @final */ CORNER: 'corner', /** * @property {String} CORNERS * @final */ CORNERS: 'corners', /** * @property {String} RADIUS * @final */ RADIUS: 'radius', /** * @property {String} RIGHT * @final */ RIGHT: 'right', /** * @property {String} LEFT * @final */ LEFT: 'left', /** * @property {String} CENTER * @final */ CENTER: 'center', /** * @property {String} TOP * @final */ TOP: 'top', /** * @property {String} BOTTOM * @final */ BOTTOM: 'bottom', /** * @property {String} BASELINE * @final * @default alphabetic */ BASELINE: 'alphabetic', /** * @property {Number} POINTS * @final * @default 0x0000 */ POINTS: 0x0000, /** * @property {Number} LINES * @final * @default 0x0001 */ LINES: 0x0001, /** * @property {Number} LINE_STRIP * @final * @default 0x0003 */ LINE_STRIP: 0x0003, /** * @property {Number} LINE_LOOP * @final * @default 0x0002 */ LINE_LOOP: 0x0002, /** * @property {Number} TRIANGLES * @final * @default 0x0004 */ TRIANGLES: 0x0004, /** * @property {Number} TRIANGLE_FAN * @final * @default 0x0006 */ TRIANGLE_FAN: 0x0006, /** * @property {Number} TRIANGLE_STRIP * @final * @default 0x0005 */ TRIANGLE_STRIP: 0x0005, /** * @property {String} QUADS * @final */ QUADS: 'quads', /** * @property {String} QUAD_STRIP * @final * @default quad_strip */ QUAD_STRIP: 'quad_strip', /** * @property {String} CLOSE * @final */ CLOSE: 'close', /** * @property {String} OPEN * @final */ OPEN: 'open', /** * @property {String} CHORD * @final */ CHORD: 'chord', /** * @property {String} PIE * @final */ PIE: 'pie', /** * @property {String} PROJECT * @final * @default square */ PROJECT: 'square', // PEND: careful this is counterintuitive /** * @property {String} SQUARE * @final * @default butt */ SQUARE: 'butt', /** * @property {String} ROUND * @final */ ROUND: 'round', /** * @property {String} BEVEL * @final */ BEVEL: 'bevel', /** * @property {String} MITER * @final */ MITER: 'miter', // COLOR /** * @property {String} RGB * @final */ RGB: 'rgb', /** * @property {String} HSB * @final */ HSB: 'hsb', /** * @property {String} HSL * @final */ HSL: 'hsl', // DOM EXTENSION AUTO: 'auto', // INPUT ALT: 18, BACKSPACE: 8, CONTROL: 17, DELETE: 46, DOWN_ARROW: 40, ENTER: 13, ESCAPE: 27, LEFT_ARROW: 37, OPTION: 18, RETURN: 13, RIGHT_ARROW: 39, SHIFT: 16, TAB: 9, UP_ARROW: 38, // RENDERING /** * @property {String} BLEND * @final * @default source-over */ BLEND: 'source-over', /** * @property {String} ADD * @final * @default lighter */ ADD: 'lighter', //ADD: 'add', // //SUBTRACT: 'subtract', // /** * @property {String} DARKEST * @final */ DARKEST: 'darken', /** * @property {String} LIGHTEST * @final * @default lighten */ LIGHTEST: 'lighten', /** * @property {String} DIFFERENCE * @final */ DIFFERENCE: 'difference', /** * @property {String} EXCLUSION * @final */ EXCLUSION: 'exclusion', /** * @property {String} MULTIPLY * @final */ MULTIPLY: 'multiply', /** * @property {String} SCREEN * @final */ SCREEN: 'screen', /** * @property {String} REPLACE * @final * @default copy */ REPLACE: 'copy', /** * @property {String} OVERLAY * @final */ OVERLAY: 'overlay', /** * @property {String} HARD_LIGHT * @final */ HARD_LIGHT: 'hard-light', /** * @property {String} SOFT_LIGHT * @final */ SOFT_LIGHT: 'soft-light', /** * @property {String} DODGE * @final * @default color-dodge */ DODGE: 'color-dodge', /** * @property {String} BURN * @final * @default color-burn */ BURN: 'color-burn', // FILTERS /** * @property {String} THRESHOLD * @final */ THRESHOLD: 'threshold', /** * @property {String} GRAY * @final */ GRAY: 'gray', /** * @property {String} OPAQUE * @final */ OPAQUE: 'opaque', /** * @property {String} INVERT * @final */ INVERT: 'invert', /** * @property {String} POSTERIZE * @final */ POSTERIZE: 'posterize', /** * @property {String} DILATE * @final */ DILATE: 'dilate', /** * @property {String} ERODE * @final */ ERODE: 'erode', /** * @property {String} BLUR * @final */ BLUR: 'blur', // TYPOGRAPHY /** * @property {String} NORMAL * @final */ NORMAL: 'normal', /** * @property {String} ITALIC * @final */ ITALIC: 'italic', /** * @property {String} BOLD * @final */ BOLD: 'bold', // TYPOGRAPHY-INTERNAL _DEFAULT_TEXT_FILL: '#000000', _DEFAULT_LEADMULT: 1.25, _CTX_MIDDLE: 'middle', // VERTICES LINEAR: 'linear', QUADRATIC: 'quadratic', BEZIER: 'bezier', CURVE: 'curve', // DEVICE-ORIENTATION /** * @property {String} LANDSCAPE * @final */ LANDSCAPE: 'landscape', /** * @property {String} PORTRAIT * @final */ PORTRAIT: 'portrait', // DEFAULTS _DEFAULT_STROKE: '#000000', _DEFAULT_FILL: '#FFFFFF' }; },{}],5:[function(_dereq_,module,exports){ /** * @module Structure * @submodule Structure * @for p5 * @requires constants */ 'use strict'; _dereq_('./shim'); // Core needs the PVariables object var constants = _dereq_('./constants'); /** * This is the p5 instance constructor. * * A p5 instance holds all the properties and methods related to * a p5 sketch. It expects an incoming sketch closure and it can also * take an optional node parameter for attaching the generated p5 canvas * to a node. The sketch closure takes the newly created p5 instance as * its sole argument and may optionally set preload(), setup(), and/or * draw() properties on it for running a sketch. * * A p5 sketch can run in "global" or "instance" mode: * "global" - all properties and methods are attached to the window * "instance" - all properties and methods are bound to this p5 object * * @param {function} sketch a closure that can set optional preload(), * setup(), and/or draw() properties on the * given p5 instance * @param {HTMLElement|boolean} [node] element to attach canvas to, if a * boolean is passed in use it as sync * @param {boolean} [sync] start synchronously (optional) * @return {p5} a p5 instance */ var p5 = function(sketch, node, sync) { if (arguments.length === 2 && typeof node === 'boolean') { sync = node; node = undefined; } ////////////////////////////////////////////// // PUBLIC p5 PROPERTIES AND METHODS ////////////////////////////////////////////// /** * Called directly before setup(), the preload() function is used to handle * asynchronous loading of external files. If a preload function is * defined, setup() will wait until any load calls within have finished. * Nothing besides load calls should be inside preload (loadImage, * loadJSON, loadFont, loadStrings, etc).

* By default the text "loading..." will be displayed. To make your own * loading page, include an HTML element with id "p5_loading" in your * page. More information here. * * @method preload * @example *
* var img; * var c; * function preload() { // preload() runs once * img = loadImage('assets/laDefense.jpg'); * } * * function setup() { // setup() waits until preload() is done * img.loadPixels(); * // get color of middle pixel * c = img.get(img.width/2, img.height/2); * } * * function draw() { * background(c); * image(img, 25, 25, 50, 50); * } *
* * @alt * nothing displayed * */ /** * The setup() function is called once when the program starts. It's used to * define initial environment properties such as screen size and background * color and to load media such as images and fonts as the program starts. * There can only be one setup() function for each program and it shouldn't * be called again after its initial execution. *

* Note: Variables declared within setup() are not accessible within other * functions, including draw(). * * @method setup * @example *
* var a = 0; * * function setup() { * background(0); * noStroke(); * fill(102); * } * * function draw() { * rect(a++%width, 10, 2, 80); * } *
* * @alt * nothing displayed * */ /** * Called directly after setup(), the draw() function continuously executes * the lines of code contained inside its block until the program is stopped * or noLoop() is called. Note if noLoop() is called in setup(), draw() will * still be executed once before stopping. draw() is called automatically and * should never be called explicitly. *

* It should always be controlled with noLoop(), redraw() and loop(). After * noLoop() stops the code in draw() from executing, redraw() causes the * code inside draw() to execute once, and loop() will cause the code * inside draw() to resume executing continuously. *

* The number of times draw() executes in each second may be controlled with * the frameRate() function. *

* There can only be one draw() function for each sketch, and draw() must * exist if you want the code to run continuously, or to process events such * as mousePressed(). Sometimes, you might have an empty call to draw() in * your program, as shown in the above example. *

* It is important to note that the drawing coordinate system will be reset * at the beginning of each draw() call. If any transformations are performed * within draw() (ex: scale, rotate, translate, their effects will be * undone at the beginning of draw(), so transformations will not accumulate * over time. On the other hand, styling applied (ex: fill, stroke, etc) will * remain in effect. * * @method draw * @example *
* var yPos = 0; * function setup() { // setup() runs once * frameRate(30); * } * function draw() { // draw() loops forever, until stopped * background(204); * yPos = yPos - 1; * if (yPos < 0) { * yPos = height; * } * line(0, yPos, width, yPos); * } *
* * @alt * nothing displayed * */ ////////////////////////////////////////////// // PRIVATE p5 PROPERTIES AND METHODS ////////////////////////////////////////////// this._setupDone = false; // for handling hidpi this._pixelDensity = Math.ceil(window.devicePixelRatio) || 1; this._userNode = node; this._curElement = null; this._elements = []; this._requestAnimId = 0; this._preloadCount = 0; this._isGlobal = false; this._loop = true; this._styles = []; this._defaultCanvasSize = { width: 100, height: 100 }; this._events = { // keep track of user-events for unregistering later 'mousemove': null, 'mousedown': null, 'mouseup': null, 'dragend': null, 'dragover': null, 'click': null, 'mouseover': null, 'mouseout': null, 'keydown': null, 'keyup': null, 'keypress': null, 'touchstart': null, 'touchmove': null, 'touchend': null, 'resize': null, 'blur': null }; this._events.wheel = null; this._loadingScreenId = 'p5_loading'; if (window.DeviceOrientationEvent) { this._events.deviceorientation = null; } if (window.DeviceMotionEvent && !window._isNodeWebkit) { this._events.devicemotion = null; } this._start = function () { // Find node if id given if (this._userNode) { if (typeof this._userNode === 'string') { this._userNode = document.getElementById(this._userNode); } } var userPreload = this.preload || window.preload; // look for "preload" if (userPreload) { // Setup loading screen // Set loading scfeen into dom if not present // Otherwise displays and removes user provided loading screen var loadingScreen = document.getElementById(this._loadingScreenId); if(!loadingScreen){ loadingScreen = document.createElement('div'); loadingScreen.innerHTML = 'Loading...'; loadingScreen.style.position = 'absolute'; loadingScreen.id = this._loadingScreenId; var node = this._userNode || document.body; node.appendChild(loadingScreen); } // var methods = this._preloadMethods; for (var method in this._preloadMethods){ // default to p5 if no object defined this._preloadMethods[method] = this._preloadMethods[method] || p5; var obj = this._preloadMethods[method]; //it's p5, check if it's global or instance if (obj === p5.prototype || obj === p5){ obj = this._isGlobal ? window : this; } this._registeredPreloadMethods[method] = obj[method]; obj[method] = this._wrapPreload(obj, method); } userPreload(); this._runIfPreloadsAreDone(); } else { this._setup(); this._runFrames(); this._draw(); } }.bind(this); this._runIfPreloadsAreDone = function(){ var context = this._isGlobal ? window : this; if (context._preloadCount === 0) { var loadingScreen = document.getElementById(context._loadingScreenId); if (loadingScreen) { loadingScreen.parentNode.removeChild(loadingScreen); } context._setup(); context._runFrames(); context._draw(); } }; this._decrementPreload = function(){ var context = this._isGlobal ? window : this; if(typeof context.preload === 'function'){ context._setProperty('_preloadCount', context._preloadCount - 1); context._runIfPreloadsAreDone(); } }; this._wrapPreload = function(obj, fnName){ return function(){ //increment counter this._incrementPreload(); //call original function var args = new Array(arguments.length); for (var i = 0; i < args.length; ++i) { args[i] = arguments[i]; } // args.push(this._decrementPreload.bind(this)); return this._registeredPreloadMethods[fnName].apply(obj, args); }.bind(this); }; this._incrementPreload = function(){ var context = this._isGlobal ? window : this; context._setProperty('_preloadCount', context._preloadCount + 1); }; this._setup = function() { // Always create a default canvas. // Later on if the user calls createCanvas, this default one // will be replaced this.createCanvas( this._defaultCanvasSize.width, this._defaultCanvasSize.height, 'p2d', true ); // return preload functions to their normal vals if switched by preload var context = this._isGlobal ? window : this; if (typeof context.preload === 'function') { for (var f in this._preloadMethods) { context[f] = this._preloadMethods[f][f]; if (context[f] && this) { context[f] = context[f].bind(this); } } } // Short-circuit on this, in case someone used the library in "global" // mode earlier if (typeof context.setup === 'function') { context.setup(); } // unhide any hidden canvases that were created var canvases = document.getElementsByTagName('canvas'); for (var i = 0; i < canvases.length; i++) { var k = canvases[i]; if (k.dataset.hidden === 'true') { k.style.visibility = ''; delete(k.dataset.hidden); } } this._setupDone = true; }.bind(this); this._draw = function () { var now = window.performance.now(); var time_since_last = now - this._lastFrameTime; var target_time_between_frames = 1000 / this._targetFrameRate; // only draw if we really need to; don't overextend the browser. // draw if we're within 5ms of when our next frame should paint // (this will prevent us from giving up opportunities to draw // again when it's really about time for us to do so). fixes an // issue where the frameRate is too low if our refresh loop isn't // in sync with the browser. note that we have to draw once even // if looping is off, so we bypass the time delay if that // is the case. var epsilon = 5; if (!this._loop || time_since_last >= target_time_between_frames - epsilon) { //mandatory update values(matrixs and stack) this._setProperty('frameCount', this.frameCount + 1); this.redraw(); this._frameRate = 1000.0/(now - this._lastFrameTime); this._lastFrameTime = now; // If the user is actually using mouse module, then update // coordinates, otherwise skip. We can test this by simply // checking if any of the mouse functions are available or not. // NOTE : This reflects only in complete build or modular build. if(typeof this._updateMouseCoords !== 'undefined') { this._updateMouseCoords(); } } // get notified the next time the browser gives us // an opportunity to draw. if (this._loop) { this._requestAnimId = window.requestAnimationFrame(this._draw); } }.bind(this); this._runFrames = function() { if (this._updateInterval) { clearInterval(this._updateInterval); } }.bind(this); this._setProperty = function(prop, value) { this[prop] = value; if (this._isGlobal) { window[prop] = value; } }.bind(this); /** * Removes the entire p5 sketch. This will remove the canvas and any * elements created by p5.js. It will also stop the draw loop and unbind * any properties or methods from the window global scope. It will * leave a variable p5 in case you wanted to create a new p5 sketch. * If you like, you can set p5 = null to erase it. * @method remove * @example *
* function draw() { * ellipse(50, 50, 10, 10); * } * * function mousePressed() { * remove(); // remove whole sketch on mouse press * } *
* * @alt * nothing displayed * */ this.remove = function() { if (this._curElement) { // stop draw this._loop = false; if (this._requestAnimId) { window.cancelAnimationFrame(this._requestAnimId); } // unregister events sketch-wide for (var ev in this._events) { window.removeEventListener(ev, this._events[ev]); } // remove DOM elements created by p5, and listeners for (var i=0; i
Bezier curves were developed by French * automotive engineer Pierre Bezier, and are commonly used in computer * graphics to define gently sloping curves. See also curve(). * * @method bezier * @param {Number} x1 x-coordinate for the first anchor point * @param {Number} y1 y-coordinate for the first anchor point * @param {Number} x2 x-coordinate for the first control point * @param {Number} y2 y-coordinate for the first control point * @param {Number} x3 x-coordinate for the second control point * @param {Number} y3 y-coordinate for the second control point * @param {Number} x4 x-coordinate for the second anchor point * @param {Number} y4 y-coordinate for the second anchor point * @return {p5} the p5 object * @example *
* * noFill(); * stroke(255, 102, 0); * line(85, 20, 10, 10); * line(90, 90, 15, 80); * stroke(0, 0, 0); * bezier(85, 20, 10, 10, 90, 90, 15, 80); * *
* @alt * stretched black s-shape in center with orange lines extending from end points. * stretched black s-shape with 10 5x5 white ellipses along the shape. * stretched black s-shape with 7 5x5 ellipses and orange lines along the shape. * stretched black s-shape with 17 small orange lines extending from under shape. * horseshoe shape with orange ends facing left and black curved center. * horseshoe shape with orange ends facing left and black curved center. * Line shaped like right-facing arrow,points move with mouse-x and warp shape. * horizontal line that hooks downward on the right and 13 5x5 ellipses along it. * right curving line mid-right of canvas with 7 short lines radiating from it. */ /** * @method bezier * @param {Number} z1 z-coordinate for the first anchor point * @param {Number} z2 z-coordinate for the first control point * @param {Number} z3 z-coordinate for the first anchor point * @param {Number} z4 z-coordinate for the first control point * @chainable * @example *
* *background(0, 0, 0); *noFill(); *stroke(255); *bezier(250,250,0, 100,100,0, 100,0,0, 0,100,0); * *
*/ p5.prototype.bezier = function() { var args = new Array(arguments.length); for (var i = 0; i < args.length; ++i) { args[i] = arguments[i]; } if (!this._renderer._doStroke && !this._renderer._doFill) { return this; } if (this._renderer.isP3D){ args.push(bezierDetail);//adding value of bezier detail to the args array this._renderer.bezier(args); } else{ this._renderer.bezier(args[0],args[1], args[2],args[3], args[4],args[5], args[6],args[7]); } return this; }; /** * Sets the resolution at which Beziers display. * * The default value is 20. * * @param {Number} detail resolution of the curves * @chainable * @example *
* * background(204); * bezierDetail(50); * bezier(85, 20, 10, 10, 90, 90, 15, 80); * *
* * @alt * stretched black s-shape with 7 5x5 ellipses and orange lines along the shape. * */ p5.prototype.bezierDetail = function(d) { bezierDetail = d; return this; }; /** * Evaluates the Bezier at position t for points a, b, c, d. * The parameters a and d are the first and last points * on the curve, and b and c are the control points. * The final parameter t varies between 0 and 1. * This can be done once with the x coordinates and a second time * with the y coordinates to get the location of a bezier curve at t. * * @method bezierPoint * @param {Number} a coordinate of first point on the curve * @param {Number} b coordinate of first control point * @param {Number} c coordinate of second control point * @param {Number} d coordinate of second point on the curve * @param {Number} t value between 0 and 1 * @return {Number} the value of the Bezier at position t * @example *
* * noFill(); * x1 = 85, x2 = 10, x3 = 90, x4 = 15; * y1 = 20, y2 = 10, y3 = 90, y4 = 80; * bezier(x1, y1, x2, y2, x3, y3, x4, y4); * fill(255); * steps = 10; * for (i = 0; i <= steps; i++) { * t = i / steps; * x = bezierPoint(x1, x2, x3, x4, t); * y = bezierPoint(y1, y2, y3, y4, t); * ellipse(x, y, 5, 5); * } * *
* * @alt * stretched black s-shape with 17 small orange lines extending from under shape. * */ p5.prototype.bezierPoint = function(a, b, c, d, t) { var adjustedT = 1-t; return Math.pow(adjustedT,3)*a + 3*(Math.pow(adjustedT,2))*t*b + 3*adjustedT*Math.pow(t,2)*c + Math.pow(t,3)*d; }; /** * Evaluates the tangent to the Bezier at position t for points a, b, c, d. * The parameters a and d are the first and last points * on the curve, and b and c are the control points. * The final parameter t varies between 0 and 1. * * @method bezierTangent * @param {Number} a coordinate of first point on the curve * @param {Number} b coordinate of first control point * @param {Number} c coordinate of second control point * @param {Number} d coordinate of second point on the curve * @param {Number} t value between 0 and 1 * @return {Number} the tangent at position t * @example *
* * noFill(); * bezier(85, 20, 10, 10, 90, 90, 15, 80); * steps = 6; * fill(255); * for (i = 0; i <= steps; i++) { * t = i / steps; * // Get the location of the point * x = bezierPoint(85, 10, 90, 15, t); * y = bezierPoint(20, 10, 90, 80, t); * // Get the tangent points * tx = bezierTangent(85, 10, 90, 15, t); * ty = bezierTangent(20, 10, 90, 80, t); * // Calculate an angle from the tangent points * a = atan2(ty, tx); * a += PI; * stroke(255, 102, 0); * line(x, y, cos(a)*30 + x, sin(a)*30 + y); * // The following line of code makes a line * // inverse of the above line * //line(x, y, cos(a)*-30 + x, sin(a)*-30 + y); * stroke(0); * ellipse(x, y, 5, 5); * } * *
* *
* * noFill(); * bezier(85, 20, 10, 10, 90, 90, 15, 80); * stroke(255, 102, 0); * steps = 16; * for (i = 0; i <= steps; i++) { * t = i / steps; * x = bezierPoint(85, 10, 90, 15, t); * y = bezierPoint(20, 10, 90, 80, t); * tx = bezierTangent(85, 10, 90, 15, t); * ty = bezierTangent(20, 10, 90, 80, t); * a = atan2(ty, tx); * a -= HALF_PI; * line(x, y, cos(a)*8 + x, sin(a)*8 + y); * } * *
* * @alt * s-shaped line with 17 short orange lines extending from underside of shape * */ p5.prototype.bezierTangent = function(a, b, c, d, t) { var adjustedT = 1-t; return 3*d*Math.pow(t,2) - 3*c*Math.pow(t,2) + 6*c*adjustedT*t - 6*b*adjustedT*t + 3*b*Math.pow(adjustedT,2) - 3*a*Math.pow(adjustedT,2); }; /** * Draws a curved line on the screen between two points, given as the * middle four parameters. The first two parameters are a control point, as * if the curve came from this point even though it's not drawn. The last * two parameters similarly describe the other control point.

* Longer curves can be created by putting a series of curve() functions * together or using curveVertex(). An additional function called * curveTightness() provides control for the visual quality of the curve. * The curve() function is an implementation of Catmull-Rom splines. * * @method curve * @param {Number} x1 x-coordinate for the beginning control point * @param {Number} y1 y-coordinate for the beginning control point * @param {Number} x2 x-coordinate for the first point * @param {Number} y2 y-coordinate for the first point * @param {Number} x3 x-coordinate for the second point * @param {Number} y3 y-coordinate for the second point * @param {Number} x4 x-coordinate for the ending control point * @param {Number} y4 y-coordinate for the ending control point * @return {p5} the p5 object * @example *
* * noFill(); * stroke(255, 102, 0); * curve(5, 26, 5, 26, 73, 24, 73, 61); * stroke(0); * curve(5, 26, 73, 24, 73, 61, 15, 65); * stroke(255, 102, 0); * curve(73, 24, 73, 61, 15, 65, 15, 65); * *
*
* * // Define the curve points as JavaScript objects * p1 = {x: 5, y: 26}, p2 = {x: 73, y: 24} * p3 = {x: 73, y: 61}, p4 = {x: 15, y: 65} * noFill(); * stroke(255, 102, 0); * curve(p1.x, p1.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y) * stroke(0); * curve(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y) * stroke(255, 102, 0); * curve(p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, p4.x, p4.y) * *
* * @alt * horseshoe shape with orange ends facing left and black curved center. * horseshoe shape with orange ends facing left and black curved center. * */ /** * @method curve * @param {Number} z1 z-coordinate for the beginning control point * @param {Number} z2 z-coordinate for the first point * @param {Number} z3 z-coordinate for the second point * @param {Number} z4 z-coordinate for the ending control point * @chainable * @example *
* * noFill(); * stroke(255, 102, 0); * curve(5,26,0, 5,26,0, 73,24,0, 73,61,0); * stroke(0); * curve(5,26,0, 73,24,0, 73,61,0, 15,65,0); * stroke(255, 102, 0); * curve(73,24,0, 73,61,0, 15,65,0, 15,65,0); * *
* * @alt * curving black and orange lines. */ p5.prototype.curve = function() { var args = new Array(arguments.length); for (var i = 0; i < args.length; ++i) { args[i] = arguments[i]; } if (!this._renderer._doStroke) { return this; } if (this._renderer.isP3D){ args.push(curveDetail); this._renderer.curve(args); } else{ this._renderer.curve(args[0],args[1], args[2],args[3], args[4],args[5], args[6],args[7]); } return this; }; /** * Sets the resolution at which curves display. * * The default value is 20. * * @param {Number} resolution of the curves * @chainable * @example *
* * background(204); * curveDetail(20); * curve(5, 26, 5, 26, 73, 24, 73, 61); * *
* * @alt * white arch shape in top-mid canvas. * */ p5.prototype.curveDetail = function(d) { curveDetail = d; return this; }; /** * Modifies the quality of forms created with curve() and curveVertex(). * The parameter tightness determines how the curve fits to the vertex * points. The value 0.0 is the default value for tightness (this value * defines the curves to be Catmull-Rom splines) and the value 1.0 connects * all the points with straight lines. Values within the range -5.0 and 5.0 * will deform the curves but will leave them recognizable and as values * increase in magnitude, they will continue to deform. * * @method curveTightness * @param {Number} amount of deformation from the original vertices * @chainable * @example *
* * // Move the mouse left and right to see the curve change * * function setup() { * createCanvas(100, 100); * noFill(); * } * * function draw() { * background(204); * var t = map(mouseX, 0, width, -5, 5); * curveTightness(t); * beginShape(); * curveVertex(10, 26); * curveVertex(10, 26); * curveVertex(83, 24); * curveVertex(83, 61); * curveVertex(25, 65); * curveVertex(25, 65); * endShape(); * } * *
* * @alt * Line shaped like right-facing arrow,points move with mouse-x and warp shape. */ p5.prototype.curveTightness = function (t) { this._renderer._curveTightness = t; }; /** * Evaluates the curve at position t for points a, b, c, d. * The parameter t varies between 0 and 1, a and d are points * on the curve, and b and c are the control points. * This can be done once with the x coordinates and a second time * with the y coordinates to get the location of a curve at t. * * @method curvePoint * @param {Number} a coordinate of first point on the curve * @param {Number} b coordinate of first control point * @param {Number} c coordinate of second control point * @param {Number} d coordinate of second point on the curve * @param {Number} t value between 0 and 1 * @return {Number} bezier value at position t * @example *
* * noFill(); * curve(5, 26, 5, 26, 73, 24, 73, 61); * curve(5, 26, 73, 24, 73, 61, 15, 65); * fill(255); * ellipseMode(CENTER); * steps = 6; * for (i = 0; i <= steps; i++) { * t = i / steps; * x = curvePoint(5, 5, 73, 73, t); * y = curvePoint(26, 26, 24, 61, t); * ellipse(x, y, 5, 5); * x = curvePoint(5, 73, 73, 15, t); * y = curvePoint(26, 24, 61, 65, t); * ellipse(x, y, 5, 5); * } * *
* *line hooking down to right-bottom with 13 5x5 white ellipse points */ p5.prototype.curvePoint = function(a, b, c, d, t) { var t3 = t*t*t, t2 = t*t, f1 = -0.5 * t3 + t2 - 0.5 * t, f2 = 1.5 * t3 - 2.5 * t2 + 1.0, f3 = -1.5 * t3 + 2.0 * t2 + 0.5 * t, f4 = 0.5 * t3 - 0.5 * t2; return a*f1 + b*f2 + c*f3 + d*f4; }; /** * Evaluates the tangent to the curve at position t for points a, b, c, d. * The parameter t varies between 0 and 1, a and d are points on the curve, * and b and c are the control points. * * @method curveTangent * @param {Number} a coordinate of first point on the curve * @param {Number} b coordinate of first control point * @param {Number} c coordinate of second control point * @param {Number} d coordinate of second point on the curve * @param {Number} t value between 0 and 1 * @return {Number} the tangent at position t * @example *
* * noFill(); * curve(5, 26, 73, 24, 73, 61, 15, 65); * steps = 6; * for (i = 0; i <= steps; i++) { * t = i / steps; * x = curvePoint(5, 73, 73, 15, t); * y = curvePoint(26, 24, 61, 65, t); * //ellipse(x, y, 5, 5); * tx = curveTangent(5, 73, 73, 15, t); * ty = curveTangent(26, 24, 61, 65, t); * a = atan2(ty, tx); * a -= PI/2.0; * line(x, y, cos(a)*8 + x, sin(a)*8 + y); * } * *
* * @alt *right curving line mid-right of canvas with 7 short lines radiating from it. */ p5.prototype.curveTangent = function(a, b,c, d, t) { var t2 = t*t, f1 = (-3*t2)/2 + 2*t - 0.5, f2 = (9*t2)/2 - 5*t, f3 = (-9*t2)/2 + 4*t + 0.5, f4 = (3*t2)/2 - t; return a*f1 + b*f2 + c*f3 + d*f4; }; module.exports = p5; },{"./core":5,"./error_helpers":8}],7:[function(_dereq_,module,exports){ /** * @module Environment * @submodule Environment * @for p5 * @requires core * @requires constants */ 'use strict'; var p5 = _dereq_('./core'); var C = _dereq_('./constants'); var standardCursors = [C.ARROW, C.CROSS, C.HAND, C.MOVE, C.TEXT, C.WAIT]; p5.prototype._frameRate = 0; p5.prototype._lastFrameTime = window.performance.now(); p5.prototype._targetFrameRate = 60; var _windowPrint = window.print; if (window.console && console.log) { /** * The print() function writes to the console area of your browser. * This function is often helpful for looking at the data a program is * producing. This function creates a new line of text for each call to * the function. Individual elements can be * separated with quotes ("") and joined with the addition operator (+). *

* While print() is similar to console.log(), it does not directly map to * it in order to simulate easier to understand behavior than * console.log(). Due to this, it is slower. For fastest results, use * console.log(). * * @method print * @param {Any} contents any combination of Number, String, Object, Boolean, * Array to print * @example *
* var x = 10; * print("The value of x is " + x); * // prints "The value of x is 10" *
* @alt * default grey canvas */ // Converts passed args into a string and then parses that string to // simulate synchronous behavior. This is a hack and is gross. // Since this will not work on all objects, particularly circular // structures, simply console.log() on error. p5.prototype.print = function(args) { try { if (arguments.length === 0) { _windowPrint(); } else if (arguments.length > 1) { console.log.apply(console, arguments); } else { var newArgs = JSON.parse(JSON.stringify(args)); if (JSON.stringify(newArgs)==='{}'){ console.log(args); } else { console.log(newArgs); } } } catch(err) { console.log(args); } }; } else { p5.prototype.print = function() {}; } /** * The system variable frameCount contains the number of frames that have * been displayed since the program started. Inside setup() the value is 0, * after the first iteration of draw it is 1, etc. * * @property {Number} frameCount * @readOnly * @example *
* function setup() { * frameRate(30); * textSize(20); * textSize(30); * textAlign(CENTER); * } * * function draw() { * background(200); * text(frameCount, width/2, height/2); * } *
* * @alt * numbers rapidly counting upward with frame count set to 30. * */ p5.prototype.frameCount = 0; /** * Confirms if the window a p5.js program is in is "focused," meaning that * the sketch will accept mouse or keyboard input. This variable is * "true" if the window is focused and "false" if not. * * @property {Boolean} focused * @readOnly * @example *
* // To demonstrate, put two windows side by side. * // Click on the window that the p5 sketch isn't in! * function draw() { * background(200); * noStroke(); * fill(0, 200, 0); * ellipse(25, 25, 50, 50); * * if (!focused) { // or "if (focused === false)" * stroke(200,0,0); * line(0, 0, 100, 100); * line(100, 0, 0, 100); * } * } *
* * @alt * green 50x50 ellipse at top left. Red X covers canvas when page focus changes * */ p5.prototype.focused = (document.hasFocus()); /** * Sets the cursor to a predefined symbol or an image, or makes it visible * if already hidden. If you are trying to set an image as the cursor, the * recommended size is 16x16 or 32x32 pixels. It is not possible to load an * image as the cursor if you are exporting your program for the Web, and not * all MODES work with all browsers. The values for parameters x and y must * be less than the dimensions of the image. * * @method cursor * @param {String|Constant} type either ARROW, CROSS, HAND, MOVE, TEXT, or * WAIT, or path for image * @param {Number} [x] the horizontal active spot of the cursor * @param {Number} [y] the vertical active spot of the cursor * @example *
* // Move the mouse left and right across the image * // to see the cursor change from a cross to a hand * function draw() { * line(width/2, 0, width/2, height); * if (mouseX < 50) { * cursor(CROSS); * } else { * cursor(HAND); * } * } *
* * @alt * horizontal line divides canvas. cursor on left is a cross, right is hand. * */ p5.prototype.cursor = function(type, x, y) { var cursor = 'auto'; var canvas = this._curElement.elt; if (standardCursors.indexOf(type) > -1) { // Standard css cursor cursor = type; } else if (typeof type === 'string') { var coords = ''; if (x && y && (typeof x === 'number' && typeof y === 'number')) { // Note that x and y values must be unit-less positive integers < 32 // https://developer.mozilla.org/en-US/docs/Web/CSS/cursor coords = x + ' ' + y; } if ((type.substring(0, 7) === 'http://') || (type.substring(0, 8) === 'https://')) { // Image (absolute url) cursor = 'url(' + type + ') ' + coords + ', auto'; } else if (/\.(cur|jpg|jpeg|gif|png|CUR|JPG|JPEG|GIF|PNG)$/.test(type)) { // Image file (relative path) - Separated for performance reasons cursor = 'url(' + type + ') ' + coords + ', auto'; } else { // Any valid string for the css cursor property cursor = type; } } canvas.style.cursor = cursor; }; /** * Specifies the number of frames to be displayed every second. For example, * the function call frameRate(30) will attempt to refresh 30 times a second. * If the processor is not fast enough to maintain the specified rate, the * frame rate will not be achieved. Setting the frame rate within setup() is * recommended. The default rate is 60 frames per second. This is the same as * setFrameRate(val). *

* Calling frameRate() with no arguments returns the current framerate. The * draw function must run at least once before it will return a value. This * is the same as getFrameRate(). *

* Calling frameRate() with arguments that are not of the type numbers * or are non positive also returns current framerate. * * @method frameRate * @param {Number} fps number of frames to be displayed every second * @chainable */ /** * @method frameRate * @return {Number} current frameRate * @example * *
* var rectX = 0; * var fr = 30; //starting FPS * var clr; * * function setup() { * background(200); * frameRate(fr); // Attempt to refresh at starting FPS * clr = color(255,0,0); * } * * function draw() { * background(200); * rectX = rectX += 1; // Move Rectangle * * if (rectX >= width) { // If you go off screen. * if (fr == 30) { * clr = color(0,0,255); * fr = 10; * frameRate(fr); // make frameRate 10 FPS * } else { * clr = color(255,0,0); * fr = 30; * frameRate(fr); // make frameRate 30 FPS * } * rectX = 0; * } * fill(clr); * rect(rectX, 40, 20,20); * } *
* * @alt * blue rect moves left to right, followed by red rect moving faster. Loops. * */ p5.prototype.frameRate = function(fps) { if (typeof fps !== 'number' || fps < 0) { return this._frameRate; } else { this._setProperty('_targetFrameRate', fps); this._runFrames(); return this; } }; /** * Returns the current framerate. * * @return {Number} current frameRate */ p5.prototype.getFrameRate = function() { return this.frameRate(); }; /** * Specifies the number of frames to be displayed every second. For example, * the function call frameRate(30) will attempt to refresh 30 times a second. * If the processor is not fast enough to maintain the specified rate, the * frame rate will not be achieved. Setting the frame rate within setup() is * recommended. The default rate is 60 frames per second. * * Calling frameRate() with no arguments returns the current framerate. * * @param {Number} [fps] number of frames to be displayed every second */ p5.prototype.setFrameRate = function(fps) { return this.frameRate(fps); }; /** * Hides the cursor from view. * * @method noCursor * @example *
* function setup() { * noCursor(); * } * * function draw() { * background(200); * ellipse(mouseX, mouseY, 10, 10); * } *
* * * @alt * cursor becomes 10x 10 white ellipse the moves with mouse x and y. * */ p5.prototype.noCursor = function() { this._curElement.elt.style.cursor = 'none'; }; /** * System variable that stores the width of the entire screen display. This * is used to run a full-screen program on any display size. * * @property {Number} displayWidth * @readOnly * @example *
* createCanvas(displayWidth, displayHeight); *
* * @alt * cursor becomes 10x 10 white ellipse the moves with mouse x and y. * */ p5.prototype.displayWidth = screen.width; /** * System variable that stores the height of the entire screen display. This * is used to run a full-screen program on any display size. * * @property {Number} displayHeight * @readOnly * @example *
* createCanvas(displayWidth, displayHeight); *
* * @alt * no display. * */ p5.prototype.displayHeight = screen.height; /** * System variable that stores the width of the inner window, it maps to * window.innerWidth. * * @property {Number} windowWidth * @readOnly * @example *
* createCanvas(windowWidth, windowHeight); *
* * @alt * no display. * */ p5.prototype.windowWidth = getWindowWidth(); /** * System variable that stores the height of the inner window, it maps to * window.innerHeight. * * @property {Number} windowHeight * @readOnly * @example *
* createCanvas(windowWidth, windowHeight); *
*@alt * no display. * */ p5.prototype.windowHeight = getWindowHeight(); /** * The windowResized() function is called once every time the browser window * is resized. This is a good place to resize the canvas or do any other * adjustments to accommodate the new window size. * * @method windowResized * @example *
* function setup() { * createCanvas(windowWidth, windowHeight); * } * * function draw() { * background(0, 100, 200); * } * * function windowResized() { * resizeCanvas(windowWidth, windowHeight); * } *
* @alt * no display. */ p5.prototype._onresize = function(e){ this._setProperty('windowWidth', getWindowWidth()); this._setProperty('windowHeight', getWindowHeight()); var context = this._isGlobal ? window : this; var executeDefault; if (typeof context.windowResized === 'function') { executeDefault = context.windowResized(e); if (executeDefault !== undefined && !executeDefault) { e.preventDefault(); } } }; function getWindowWidth() { return window.innerWidth || document.documentElement && document.documentElement.clientWidth || document.body && document.body.clientWidth || 0; } function getWindowHeight() { return window.innerHeight || document.documentElement && document.documentElement.clientHeight || document.body && document.body.clientHeight || 0; } /** * System variable that stores the width of the drawing canvas. This value * is set by the first parameter of the createCanvas() function. * For example, the function call createCanvas(320, 240) sets the width * variable to the value 320. The value of width defaults to 100 if * createCanvas() is not used in a program. * * @property {Number} width * @readOnly */ p5.prototype.width = 0; /** * System variable that stores the height of the drawing canvas. This value * is set by the second parameter of the createCanvas() function. For * example, the function call createCanvas(320, 240) sets the height * variable to the value 240. The value of height defaults to 100 if * createCanvas() is not used in a program. * * @property {Number} height * @readOnly */ p5.prototype.height = 0; /** * If argument is given, sets the sketch to fullscreen or not based on the * value of the argument. If no argument is given, returns the current * fullscreen state. Note that due to browser restrictions this can only * be called on user input, for example, on mouse press like the example * below. * * @method fullscreen * @param {Boolean} [val] whether the sketch should be in fullscreen mode * or not * @return {Boolean} current fullscreen state * @example *
* * // Clicking in the box toggles fullscreen on and off. * function setup() { * background(200); * } * function mousePressed() { * if (mouseX > 0 && mouseX < 100 && mouseY > 0 && mouseY < 100) { * var fs = fullscreen(); * fullscreen(!fs); * } * } * *
* * @alt * no display. * */ p5.prototype.fullscreen = function(val) { // no arguments, return fullscreen or not if (typeof val === 'undefined') { return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement; } else { // otherwise set to fullscreen or not if (val) { launchFullscreen(document.documentElement); } else { exitFullscreen(); } } }; /** * Sets the pixel scaling for high pixel density displays. By default * pixel density is set to match display density, call pixelDensity(1) * to turn this off. Calling pixelDensity() with no arguments returns * the current pixel density of the sketch. * * * @method pixelDensity * @param {Number} [val] whether or how much the sketch should scale * @returns {Number} current pixel density of the sketch * @example *
* * function setup() { * pixelDensity(1); * createCanvas(100, 100); * background(200); * ellipse(width/2, height/2, 50, 50); * } * *
*
* * function setup() { * pixelDensity(3.0); * createCanvas(100, 100); * background(200); * ellipse(width/2, height/2, 50, 50); * } * *
* * @alt * fuzzy 50x50 white ellipse with black outline in center of canvas. * sharp 50x50 white ellipse with black outline in center of canvas. */ p5.prototype.pixelDensity = function(val) { if (typeof val === 'number') { this._pixelDensity = val; } else { return this._pixelDensity; } this.resizeCanvas(this.width, this.height, true); }; /** * Returns the pixel density of the current display the sketch is running on. * * @method displayDensity * @returns {Number} current pixel density of the display * @example *
* * function setup() { * var density = displayDensity(); * pixelDensity(density); * createCanvas(100, 100); * background(200); * ellipse(width/2, height/2, 50, 50); * } * *
* * @alt * 50x50 white ellipse with black outline in center of canvas. */ p5.prototype.displayDensity = function() { return window.devicePixelRatio; }; function launchFullscreen(element) { var enabled = document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled; if (!enabled) { throw new Error('Fullscreen not enabled in this browser.'); } if(element.requestFullscreen) { element.requestFullscreen(); } else if(element.mozRequestFullScreen) { element.mozRequestFullScreen(); } else if(element.webkitRequestFullscreen) { element.webkitRequestFullscreen(); } else if(element.msRequestFullscreen) { element.msRequestFullscreen(); } } function exitFullscreen() { if(document.exitFullscreen) { document.exitFullscreen(); } else if(document.mozCancelFullScreen) { document.mozCancelFullScreen(); } else if(document.webkitExitFullscreen) { document.webkitExitFullscreen(); } else if (document.msExitFullscreen) { document.msExitFullscreen(); } } /** * Gets the current URL. * @method getURL * @return {String} url * @example *
* * var url; * var x = 100; * * function setup() { * fill(0); * noStroke(); * url = getURL(); * } * * function draw() { * background(200); * text(url, x, height/2); * x--; * } * *
* * @alt * current url (http://p5js.org/reference/#/p5/getURL) moves right to left. * */ p5.prototype.getURL = function() { return location.href; }; /** * Gets the current URL path as an array. * @method getURLPath * @return {String[]} path components * @example *
* function setup() { * var urlPath = getURLPath(); * for (var i=0; i<urlPath.length; i++) { * text(urlPath[i], 10, i*20+20); * } * } *
* * @alt *no display * */ p5.prototype.getURLPath = function() { return location.pathname.split('/').filter(function(v){return v!=='';}); }; /** * Gets the current URL params as an Object. * @method getURLParams * @return {Object} URL params * @example *
* * // Example: http://p5js.org?year=2014&month=May&day=15 * * function setup() { * var params = getURLParams(); * text(params.day, 10, 20); * text(params.month, 10, 40); * text(params.year, 10, 60); * } * *
* @alt * no display. * */ p5.prototype.getURLParams = function() { var re = /[?&]([^&=]+)(?:[&=])([^&=]+)/gim; var m; var v={}; while ((m = re.exec(location.search)) != null) { if (m.index === re.lastIndex) { re.lastIndex++; } v[m[1]]=m[2]; } return v; }; module.exports = p5; },{"./constants":4,"./core":5}],8:[function(_dereq_,module,exports){ /** * @for p5 * @requires core */ 'use strict'; var p5 = _dereq_('./core'); var doFriendlyWelcome = false; // TEMP until we get it all working LM // -- Borrowed from jQuery 1.11.3 -- var class2type = {}; var toString = class2type.toString; var names = ['Boolean', 'Number', 'String', 'Function', 'Array', 'Date', 'RegExp', 'Object', 'Error']; for (var n=0; n p5.js says: '+message+'%c'+ // '[https://github.com/processing/p5.js/wiki/Local-server]', // 'background-color:' + color + ';color:#FFF;', // 'background-color:transparent;color:' + color +';', // 'background-color:' + color + ';color:#FFF;', // 'background-color:transparent;color:' + color +';' // ); // } // else{ // console.log( // '%c> p5.js says: '+message+'%c [http://p5js.org/reference/#p5/'+func+ // ']', 'background-color:' + color + ';color:#FFF;', // 'background-color:transparent;color:' + color +';' // ); // } } var errorCases = { '0': { fileType: 'image', method: 'loadImage', message: ' hosting the image online,' }, '1': { fileType: 'XML file', method: 'loadXML' }, '2': { fileType: 'table file', method: 'loadTable' }, '3': { fileType: 'text file', method: 'loadStrings' }, '4': { fileType: 'font', method: 'loadFont', message: ' hosting the font online,' }, }; p5._friendlyFileLoadError = function (errorType, filePath) { var errorInfo = errorCases[ errorType ]; var message = 'It looks like there was a problem' + ' loading your ' + errorInfo.fileType + '.' + ' Try checking if the file path%c [' + filePath + '] %cis correct,' + (errorInfo.message || '') + ' or running a local server.'; report(message, errorInfo.method, FILE_LOAD); }; function friendlyWelcome() { // p5.js brand - magenta: #ED225D var astrixBgColor = 'transparent'; var astrixTxtColor = '#ED225D'; var welcomeBgColor = '#ED225D'; var welcomeTextColor = 'white'; console.log( '%c _ \n'+ ' /\\| |/\\ \n'+ ' \\ ` \' / \n'+ ' / , . \\ \n'+ ' \\/|_|\\/ '+ '\n\n%c> p5.js says: Welcome! '+ 'This is your friendly debugger. ' + 'To turn me off switch to using “p5.min.js”.', 'background-color:'+astrixBgColor+';color:' + astrixTxtColor +';', 'background-color:'+welcomeBgColor+';color:' + welcomeTextColor +';' ); } /** * Prints out all the colors in the color pallete with white text. * For color blindness testing. */ /* function testColors() { var str = 'A box of biscuits, a box of mixed biscuits and a biscuit mixer'; report(str, 'print', '#ED225D'); // p5.js magenta report(str, 'print', '#2D7BB6'); // p5.js blue report(str, 'print', '#EE9900'); // p5.js orange report(str, 'print', '#A67F59'); // p5.js light brown report(str, 'print', '#704F21'); // p5.js gold report(str, 'print', '#1CC581'); // auto cyan report(str, 'print', '#FF6625'); // auto orange report(str, 'print', '#79EB22'); // auto green report(str, 'print', '#B40033'); // p5.js darkened magenta report(str, 'print', '#084B7F'); // p5.js darkened blue report(str, 'print', '#945F00'); // p5.js darkened orange report(str, 'print', '#6B441D'); // p5.js darkened brown report(str, 'print', '#2E1B00'); // p5.js darkened gold report(str, 'print', '#008851'); // auto dark cyan report(str, 'print', '#C83C00'); // auto dark orange report(str, 'print', '#4DB200'); // auto dark green } */ // This is a lazily-defined list of p5 symbols that may be // misused by beginners at top-level code, outside of setup/draw. We'd like // to detect these errors and help the user by suggesting they move them // into setup/draw. // // For more details, see https://github.com/processing/p5.js/issues/1121. var misusedAtTopLevelCode = null; var FAQ_URL = 'https://github.com/processing/p5.js/wiki/' + 'Frequently-Asked-Questions' + '#why-cant-i-assign-variables-using-p5-functions-and-' + 'variables-before-setup'; function defineMisusedAtTopLevelCode() { var uniqueNamesFound = {}; var getSymbols = function(obj) { return Object.getOwnPropertyNames(obj).filter(function(name) { if (name[0] === '_') { return false; } if (name in uniqueNamesFound) { return false; } uniqueNamesFound[name] = true; return true; }).map(function(name) { var type; if (typeof(obj[name]) === 'function') { type = 'function'; } else if (name === name.toUpperCase()) { type = 'constant'; } else { type = 'variable'; } return {name: name, type: type}; }); }; misusedAtTopLevelCode = [].concat( getSymbols(p5.prototype), // At present, p5 only adds its constants to p5.prototype during // construction, which may not have happened at the time a // ReferenceError is thrown, so we'll manually add them to our list. getSymbols(_dereq_('./constants')) ); // This will ultimately ensure that we report the most specific error // possible to the user, e.g. advising them about HALF_PI instead of PI // when their code misuses the former. misusedAtTopLevelCode.sort(function(a, b) { return b.name.length - a.name.length; }); } function helpForMisusedAtTopLevelCode(e, log) { if (!log) { log = console.log.bind(console); } if (!misusedAtTopLevelCode) { defineMisusedAtTopLevelCode(); } // If we find that we're logging lots of false positives, we can // uncomment the following code to avoid displaying anything if the // user's code isn't likely to be using p5's global mode. (Note that // setup/draw are more likely to be defined due to JS function hoisting.) // //if (!('setup' in window || 'draw' in window)) { // return; //} misusedAtTopLevelCode.some(function(symbol) { // Note that while just checking for the occurrence of the // symbol name in the error message could result in false positives, // a more rigorous test is difficult because different browsers // log different messages, and the format of those messages may // change over time. // // For example, if the user uses 'PI' in their code, it may result // in any one of the following messages: // // * 'PI' is undefined (Microsoft Edge) // * ReferenceError: PI is undefined (Firefox) // * Uncaught ReferenceError: PI is not defined (Chrome) if (e.message && e.message.match('\\W?'+symbol.name+'\\W') !== null) { log('%cDid you just try to use p5.js\'s ' + symbol.name + (symbol.type === 'function' ? '() ' : ' ') + symbol.type + '? If so, you may want to ' + 'move it into your sketch\'s setup() function.\n\n' + 'For more details, see: ' + FAQ_URL, 'color: #B40033' /* Dark magenta */); return true; } }); } // Exposing this primarily for unit testing. p5.prototype._helpForMisusedAtTopLevelCode = helpForMisusedAtTopLevelCode; if (document.readyState !== 'complete') { window.addEventListener('error', helpForMisusedAtTopLevelCode, false); // Our job is only to catch ReferenceErrors that are thrown when // global (non-instance mode) p5 APIs are used at the top-level // scope of a file, so we'll unbind our error listener now to make // sure we don't log false positives later. window.addEventListener('load', function() { window.removeEventListener('error', helpForMisusedAtTopLevelCode, false); }); } module.exports = p5; },{"./constants":4,"./core":5}],9:[function(_dereq_,module,exports){ var p5 = _dereq_('../core/core'); /** * _globalInit * * TODO: ??? * if sketch is on window * assume "global" mode * and instantiate p5 automatically * otherwise do nothing * * @return {Undefined} */ var _globalInit = function() { if (!window.PHANTOMJS && !window.mocha) { // If there is a setup or draw function on the window // then instantiate p5 in "global" mode if(((window.setup && typeof window.setup === 'function') || (window.draw && typeof window.draw === 'function')) && !p5.instance) { new p5(); } } }; // TODO: ??? if (document.readyState === 'complete') { _globalInit(); } else { window.addEventListener('load', _globalInit , false); } },{"../core/core":5}],10:[function(_dereq_,module,exports){ /** * @module DOM * @submodule DOM * @for p5.Element */ var p5 = _dereq_('./core'); /** * Base class for all elements added to a sketch, including canvas, * graphics buffers, and other HTML elements. Methods in blue are * included in the core functionality, methods in brown are added * with the p5.dom * library. * It is not called directly, but p5.Element * objects are created by calling createCanvas, createGraphics, * or in the p5.dom library, createDiv, createImg, createInput, etc. * * @class p5.Element * @constructor * @param {String} elt DOM node that is wrapped * @param {p5} [pInst] pointer to p5 instance */ p5.Element = function(elt, pInst) { /** * Underlying HTML element. All normal HTML methods can be called on this. * * @property elt * @readOnly */ this.elt = elt; this._pInst = pInst; this._events = {}; this.width = this.elt.offsetWidth; this.height = this.elt.offsetHeight; }; /** * * Attaches the element to the parent specified. A way of setting * the container for the element. Accepts either a string ID, DOM * node, or p5.Element. If no arguments given, parent node is returned. * For more ways to position the canvas, see the * * positioning the canvas wiki page. * * @method parent * @param {String|p5.Element|Object} parent the ID, DOM node, or p5.Element * of desired parent element * @chainable */ /** * @method parent * @return {p5.Element} * * @example *
* // in the html file: * <div id="myContainer"></div> * // in the js file: * var cnv = createCanvas(100, 100); * cnv.parent("myContainer"); *
*
* var div0 = createDiv('this is the parent'); * var div1 = createDiv('this is the child'); * div1.parent(div0); // use p5.Element *
*
* var div0 = createDiv('this is the parent'); * div0.id('apples'); * var div1 = createDiv('this is the child'); * div1.parent('apples'); // use id *
*
* var elt = document.getElementById('myParentDiv'); * var div1 = createDiv('this is the child'); * div1.parent(elt); // use element from page *
* * @alt * no display. * */ p5.Element.prototype.parent = function(p) { if (arguments.length === 0){ return this.elt.parentNode; } else { if (typeof p === 'string') { if (p[0] === '#') { p = p.substring(1); } p = document.getElementById(p); } else if (p instanceof p5.Element) { p = p.elt; } p.appendChild(this.elt); return this; } }; /** * * Sets the ID of the element. If no ID argument is passed in, it instead * returns the current ID of the element. * * @method id * @param {String} id ID of the element * @chainable */ /** * @method id * @return {String} the id of the element * * @example *
* function setup() { * var cnv = createCanvas(100, 100); * // Assigns a CSS selector ID to * // the canvas element. * cnv.id("mycanvas"); * } *
* * @alt * no display. * */ p5.Element.prototype.id = function(id) { if (arguments.length === 0) { return this.elt.id; } else { this.elt.id = id; this.width = this.elt.offsetWidth; this.height = this.elt.offsetHeight; return this; } }; /** * * Adds given class to the element. If no class argument is passed in, it * instead returns a string containing the current class(es) of the element. * * @method class * @param {String} class class to add * @chainable */ /** * @method class * @return {String} the class of the element */ p5.Element.prototype.class = function(c) { if (arguments.length === 0) { return this.elt.className; } else { this.elt.className = c; return this; } }; /** * The .mousePressed() function is called once after every time a * mouse button is pressed over the element. This can be used to * attach element specific event listeners. * * @method mousePressed * @param {function} fxn function to be fired when mouse is * pressed over the element. * @chainable * @example *
* var cnv; * var d; * var g; * function setup() { * cnv = createCanvas(100, 100); * cnv.mousePressed(changeGray); // attach listener for * // canvas click only * d = 10; * g = 100; * } * * function draw() { * background(g); * ellipse(width/2, height/2, d, d); * } * * // this function fires with any click anywhere * function mousePressed() { * d = d + 10; * } * * // this function fires only when cnv is clicked * function changeGray() { * g = random(0, 255); * } *
* * @alt * no display. * */ p5.Element.prototype.mousePressed = function (fxn) { attachListener('mousedown', fxn, this); attachListener('touchstart', fxn, this); return this; }; /** * The .doubleClicked() function is called once after every time a * mouse button is pressed twice over the element. This can be used to * attach element and action specific event listeners. * * @method doubleClicked * @param {Function} fxn function to be fired when mouse is * pressed over the element. * @return {p5.Element} * @example *
* var cnv; * var d; * var g; * function setup() { * cnv = createCanvas(100, 100); * cnv.doubleClicked(changeGray); // attach listener for * // canvas click only * d = 10; * g = 100; * } * * function draw() { * background(g); * ellipse(width/2, height/2, d, d); * } * * // this function fires with any double click anywhere * function doubleClicked() { * d = d + 10; * } * * // this function fires only when cnv is clicked * function changeGray() { * g = random(0, 255); * } *
* * @alt * no display. * */ p5.Element.prototype.doubleClicked = function (fxn) { attachListener('doubleClicked', fxn, this); return this; }; /** * The .mouseWheel() function is called once after every time a * mouse wheel is scrolled over the element. This can be used to * attach element specific event listeners. *

* The function accepts a callback function as argument which will be executed * when the `wheel` event is triggered on the element, the callback function is * passed one argument `event`. The `event.deltaY` property returns negative * values if the mouse wheel is rotated up or away from the user and positive * in the other direction. The `event.deltaX` does the same as `event.deltaY` * except it reads the horizontal wheel scroll of the mouse wheel. *

* On OS X with "natural" scrolling enabled, the `event.deltaY` values are * reversed. * * @method mouseWheel * @param {function} fxn function to be fired when mouse wheel is * scrolled over the element. * @chainable * @example *
* var cnv; * var d; * var g; * function setup() { * cnv = createCanvas(100, 100); * cnv.mouseWheel(changeSize); // attach listener for * // activity on canvas only * d = 10; * g = 100; * } * * function draw() { * background(g); * ellipse(width/2, height/2, d, d); * } * * // this function fires with mousewheel movement * // anywhere on screen * function mouseWheel() { * g = g + 10; * } * * // this function fires with mousewheel movement * // over canvas only * function changeSize(event) { * if (event.deltaY > 0) { * d = d + 10; * } else { * d = d - 10; * } * } *
* * * @alt * no display. * */ p5.Element.prototype.mouseWheel = function (fxn) { attachListener('wheel', fxn, this); return this; }; /** * The .mouseReleased() function is called once after every time a * mouse button is released over the element. This can be used to * attach element specific event listeners. * * @method mouseReleased * @param {function} fxn function to be fired when mouse is * released over the element. * @chainable * @example *
* var cnv; * var d; * var g; * function setup() { * cnv = createCanvas(100, 100); * cnv.mouseReleased(changeGray); // attach listener for * // activity on canvas only * d = 10; * g = 100; * } * * function draw() { * background(g); * ellipse(width/2, height/2, d, d); * } * * // this function fires after the mouse has been * // released * function mouseReleased() { * d = d + 10; * } * * // this function fires after the mouse has been * // released while on canvas * function changeGray() { * g = random(0, 255); * } *
* * * @alt * no display. * */ p5.Element.prototype.mouseReleased = function (fxn) { attachListener('mouseup', fxn, this); attachListener('touchend', fxn, this); return this; }; /** * The .mouseClicked() function is called once after a mouse button is * pressed and released over the element. This can be used to * attach element specific event listeners. * * @method mouseClicked * @param {function} fxn function to be fired when mouse is * clicked over the element. * @chainable * @example *
* * var cnv; * var d; * var g; * * function setup() { * cnv = createCanvas(100, 100); * cnv.mouseClicked(changeGray); // attach listener for * // activity on canvas only * d = 10; * g = 100; * } * * function draw() { * background(g); * ellipse(width/2, height/2, d, d); * } * * // this function fires after the mouse has been * // clicked anywhere * function mouseClicked() { * d = d + 10; * } * * // this function fires after the mouse has been * // clicked on canvas * function changeGray() { * g = random(0, 255); * } * *
* * @alt * no display. * */ p5.Element.prototype.mouseClicked = function (fxn) { attachListener('click', fxn, this); return this; }; /** * The .mouseMoved() function is called once every time a * mouse moves over the element. This can be used to attach an * element specific event listener. * * @method mouseMoved * @param {function} fxn function to be fired when mouse is * moved over the element. * @chainable * @example *
* var cnv; * var d = 30; * var g; * function setup() { * cnv = createCanvas(100, 100); * cnv.mouseMoved(changeSize); // attach listener for * // activity on canvas only * d = 10; * g = 100; * } * * function draw() { * background(g); * fill(200); * ellipse(width/2, height/2, d, d); * } * * // this function fires when mouse moves anywhere on * // page * function mouseMoved() { * g = g + 5; * if (g > 255) { * g = 0; * } * } * * // this function fires when mouse moves over canvas * function changeSize() { * d = d + 2; * if (d > 100) { * d = 0; * } * } *
* * * @alt * no display. * */ p5.Element.prototype.mouseMoved = function (fxn) { attachListener('mousemove', fxn, this); attachListener('touchmove', fxn, this); return this; }; /** * The .mouseOver() function is called once after every time a * mouse moves onto the element. This can be used to attach an * element specific event listener. * * @method mouseOver * @param {function} fxn function to be fired when mouse is * moved over the element. * @chainable * @example *
* var cnv; * var d; * var g; * function setup() { * cnv = createCanvas(100, 100); * cnv.mouseOver(changeGray); * d = 10; * } * * function draw() { * ellipse(width/2, height/2, d, d); * } * * function changeGray() { * d = d + 10; * if (d > 100) { * d = 0; * } * } *
* * * @alt * no display. * */ p5.Element.prototype.mouseOver = function (fxn) { attachListener('mouseover', fxn, this); return this; }; /** * The .changed() function is called when the value of an * element is changed. * This can be used to attach an element specific event listener. * * @method changed * @param {function} fxn function to be fired when the value of an * element changes. * @chainable * @example *
* var sel; * * function setup() { * textAlign(CENTER); * background(200); * sel = createSelect(); * sel.position(10, 10); * sel.option('pear'); * sel.option('kiwi'); * sel.option('grape'); * sel.changed(mySelectEvent); * } * * function mySelectEvent() { * var item = sel.value(); * background(200); * text("it's a "+item+"!", 50, 50); * } *
*
* var checkbox; * var cnv; * * function setup() { * checkbox = createCheckbox(" fill"); * checkbox.changed(changeFill); * cnv = createCanvas(100, 100); * cnv.position(0, 30); * noFill(); * } * * function draw() { * background(200); * ellipse(50, 50, 50, 50); * } * * function changeFill() { * if (checkbox.checked()) { * fill(0); * } else { * noFill(); * } * } *
* * @alt * dropdown: pear, kiwi, grape. When selected text "its a" + selection shown. * */ p5.Element.prototype.changed = function (fxn) { attachListener('change', fxn, this); return this; }; /** * The .input() function is called when any user input is * detected with an element. The input event is often used * to detect keystrokes in a input element, or changes on a * slider element. This can be used to attach an element specific * event listener. * * @method input * @param {function} fxn function to be fired on user input. * @chainable * @example *
* // Open your console to see the output * function setup() { * var inp = createInput(''); * inp.input(myInputEvent); * } * * function myInputEvent() { * console.log('you are typing: ', this.value()); * } *
* * @alt * no display. * */ p5.Element.prototype.input = function (fxn) { attachListener('input', fxn, this); return this; }; /** * The .mouseOut() function is called once after every time a * mouse moves off the element. This can be used to attach an * element specific event listener. * * @method mouseOut * @param {function} fxn function to be fired when mouse is * moved off the element. * @chainable * @example *
* var cnv; * var d; * var g; * function setup() { * cnv = createCanvas(100, 100); * cnv.mouseOut(changeGray); * d = 10; * } * * function draw() { * ellipse(width/2, height/2, d, d); * } * * function changeGray() { * d = d + 10; * if (d > 100) { * d = 0; * } * } *
* * @alt * no display. * */ p5.Element.prototype.mouseOut = function (fxn) { attachListener('mouseout', fxn, this); return this; }; /** * The .touchStarted() function is called once after every time a touch is * registered. This can be used to attach element specific event listeners. * * @method touchStarted * @param {function} fxn function to be fired when touch is * started over the element. * @chainable * @example *
* var cnv; * var d; * var g; * function setup() { * cnv = createCanvas(100, 100); * cnv.touchStarted(changeGray); // attach listener for * // canvas click only * d = 10; * g = 100; * } * * function draw() { * background(g); * ellipse(width/2, height/2, d, d); * } * * // this function fires with any touch anywhere * function touchStarted() { * d = d + 10; * } * * // this function fires only when cnv is clicked * function changeGray() { * g = random(0, 255); * } *
* * @alt * no display. * */ p5.Element.prototype.touchStarted = function (fxn) { attachListener('touchstart', fxn, this); attachListener('mousedown', fxn, this); return this; }; /** * The .touchMoved() function is called once after every time a touch move is * registered. This can be used to attach element specific event listeners. * * @method touchMoved * @param {function} fxn function to be fired when touch is moved * over the element. * @chainable * @example *
* var cnv; * var g; * function setup() { * cnv = createCanvas(100, 100); * cnv.touchMoved(changeGray); // attach listener for * // canvas click only * g = 100; * } * * function draw() { * background(g); * } * * // this function fires only when cnv is clicked * function changeGray() { * g = random(0, 255); * } *
* * @alt * no display. * */ p5.Element.prototype.touchMoved = function (fxn) { attachListener('touchmove', fxn, this); attachListener('mousemove', fxn, this); return this; }; /** * The .touchEnded() function is called once after every time a touch is * registered. This can be used to attach element specific event listeners. * * @method touchEnded * @param {function} fxn function to be fired when touch is * ended over the element. * @chainable * @example *
* var cnv; * var d; * var g; * function setup() { * cnv = createCanvas(100, 100); * cnv.touchEnded(changeGray); // attach listener for * // canvas click only * d = 10; * g = 100; * } * * function draw() { * background(g); * ellipse(width/2, height/2, d, d); * } * * // this function fires with any touch anywhere * function touchEnded() { * d = d + 10; * } * * // this function fires only when cnv is clicked * function changeGray() { * g = random(0, 255); * } *
* * * @alt * no display. * */ p5.Element.prototype.touchEnded = function (fxn) { attachListener('touchend', fxn, this); attachListener('mouseup', fxn, this); return this; }; /** * The .dragOver() function is called once after every time a * file is dragged over the element. This can be used to attach an * element specific event listener. * * @method dragOver * @param {function} fxn function to be fired when mouse is * dragged over the element. * @chainable * @example *
* // To test this sketch, simply drag a * // file over the canvas * function setup() { * var c = createCanvas(100, 100); * background(200); * textAlign(CENTER); * text('Drag file', width/2, height/2); * c.dragOver(dragOverCallback); * } * * // This function will be called whenever * // a file is dragged over the canvas * function dragOverCallback() { * background(240); * text('Dragged over', width/2, height/2); * } *
* @alt * nothing displayed */ p5.Element.prototype.dragOver = function (fxn) { attachListener('dragover', fxn, this); return this; }; /** * The .dragLeave() function is called once after every time a * dragged file leaves the element area. This can be used to attach an * element specific event listener. * * @method dragLeave * @param {function} fxn function to be fired when mouse is * dragged over the element. * @chainable * @example *
* // To test this sketch, simply drag a file * // over and then out of the canvas area * function setup() { * var c = createCanvas(100, 100); * background(200); * textAlign(CENTER); * text('Drag file', width/2, height/2); * c.dragLeave(dragLeaveCallback); * } * * // This function will be called whenever * // a file is dragged out of the canvas * function dragLeaveCallback() { * background(240); * text('Dragged off', width/2, height/2); * } *
* @alt * nothing displayed */ p5.Element.prototype.dragLeave = function (fxn) { attachListener('dragleave', fxn, this); return this; }; /** * The .drop() function is called for each file dropped on the element. * It requires a callback that is passed a p5.File object. You can * optionally pass two callbacks, the first one (required) is triggered * for each file dropped when the file is loaded. The second (optional) * is triggered just once when a file (or files) are dropped. * * @method drop * @param {function} callback callback triggered when files are dropped. * @param {function} fxn callback to receive loaded file. * @chainable * @example *
* function setup() { * var c = createCanvas(100, 100); * background(200); * textAlign(CENTER); * text('drop image', width/2, height/2); * c.drop(gotFile); * } * * function gotFile(file) { * var img = createImg(file.data).hide(); * // Draw the image onto the canvas * image(img, 0, 0, width, height); * } *
* * @alt * Canvas turns into whatever image is dragged/dropped onto it. * */ p5.Element.prototype.drop = function (callback, fxn) { // Make a file loader callback and trigger user's callback function makeLoader(theFile) { // Making a p5.File object var p5file = new p5.File(theFile); return function(e) { p5file.data = e.target.result; callback(p5file); }; } // Is the file stuff supported? if (window.File && window.FileReader && window.FileList && window.Blob) { // If you want to be able to drop you've got to turn off // a lot of default behavior attachListener('dragover',function(evt) { evt.stopPropagation(); evt.preventDefault(); },this); // If this is a drag area we need to turn off the default behavior attachListener('dragleave',function(evt) { evt.stopPropagation(); evt.preventDefault(); },this); // If just one argument it's the callback for the files if (arguments.length > 1) { attachListener('drop', fxn, this); } // Deal with the files attachListener('drop', function(evt) { evt.stopPropagation(); evt.preventDefault(); // A FileList var files = evt.dataTransfer.files; // Load each one and trigger the callback for (var i = 0; i < files.length; i++) { var f = files[i]; var reader = new FileReader(); reader.onload = makeLoader(f); // Text or data? // This should likely be improved if (f.type.indexOf('text') > -1) { reader.readAsText(f); } else { reader.readAsDataURL(f); } } }, this); } else { console.log('The File APIs are not fully supported in this browser.'); } return this; }; function attachListener(ev, fxn, ctx) { // LM removing, not sure why we had this? // var _this = ctx; // var f = function (e) { fxn(e, _this); }; var f = fxn.bind(ctx); ctx.elt.addEventListener(ev, f, false); ctx._events[ev] = f; } /** * Helper fxn for sharing pixel methods * */ p5.Element.prototype._setProperty = function (prop, value) { this[prop] = value; }; module.exports = p5.Element; },{"./core":5}],11:[function(_dereq_,module,exports){ /** * @module Rendering * @submodule Rendering * @for p5 */ var p5 = _dereq_('./core'); var constants = _dereq_('./constants'); /** * Thin wrapper around a renderer, to be used for creating a * graphics buffer object. Use this class if you need * to draw into an off-screen graphics buffer. The two parameters define the * width and height in pixels. The fields and methods for this class are * extensive, but mirror the normal drawing API for p5. * * @class p5.Graphics * @constructor * @extends p5.Element * @param {Number} w width * @param {Number} h height * @param {Constant} renderer the renderer to use, either P2D or WEBGL * @param {p5} [pInst] pointer to p5 instance */ p5.Graphics = function(w, h, renderer, pInst) { var r = renderer || constants.P2D; this.canvas = document.createElement('canvas'); var node = this._userNode || document.body; node.appendChild(this.canvas); p5.Element.call(this, this.canvas, pInst, false); this._styles = []; this.width = w; this.height = h; this._pixelDensity = pInst._pixelDensity; if (r === constants.WEBGL) { this._renderer = new p5.RendererGL(this.canvas, this, false); } else { this._renderer = new p5.Renderer2D(this.canvas, this, false); } this._renderer.resize(w, h); this._renderer._applyDefaults(); pInst._elements.push(this); // bind methods and props of p5 to the new object for (var p in p5.prototype) { if (!this[p]) { if (typeof p5.prototype[p] === 'function') { this[p] = p5.prototype[p].bind(this); } else { this[p] = p5.prototype[p]; } } } return this; }; p5.Graphics.prototype = Object.create(p5.Element.prototype); p5.Graphics.prototype.remove = function() { if (this.elt.parentNode) { this.elt.parentNode.removeChild(this.elt); } for (var elt_ev in this._events) { this.elt.removeEventListener(elt_ev, this._events[elt_ev]); } }; module.exports = p5.Graphics; },{"./constants":4,"./core":5}],12:[function(_dereq_,module,exports){ /** * @module Rendering * @submodule Rendering * @for p5 */ var p5 = _dereq_('./core'); var constants = _dereq_('../core/constants'); /** * Main graphics and rendering context, as well as the base API * implementation for p5.js "core". To be used as the superclass for * Renderer2D and Renderer3D classes, respecitvely. * * @class p5.Renderer * @constructor * @extends p5.Element * @param {String} elt DOM node that is wrapped * @param {p5} [pInst] pointer to p5 instance * @param {Boolean} [isMainCanvas] whether we're using it as main canvas */ p5.Renderer = function(elt, pInst, isMainCanvas) { p5.Element.call(this, elt, pInst); this.canvas = elt; this._pInst = pInst; if (isMainCanvas) { this._isMainCanvas = true; // for pixel method sharing with pimage this._pInst._setProperty('_curElement', this); this._pInst._setProperty('canvas', this.canvas); this._pInst._setProperty('width', this.width); this._pInst._setProperty('height', this.height); } else { // hide if offscreen buffer by default this.canvas.style.display = 'none'; this._styles = []; // non-main elt styles stored in p5.Renderer } this._textSize = 12; this._textLeading = 15; this._textFont = 'sans-serif'; this._textStyle = constants.NORMAL; this._textAscent = null; this._textDescent = null; this._rectMode = constants.CORNER; this._ellipseMode = constants.CENTER; this._curveTightness = 0; this._imageMode = constants.CORNER; this._tint = null; this._doStroke = true; this._doFill = true; this._strokeSet = false; this._fillSet = false; this._colorMode = constants.RGB; this._colorMaxes = { rgb: [255, 255, 255, 255], hsb: [360, 100, 100, 1], hsl: [360, 100, 100, 1] }; }; p5.Renderer.prototype = Object.create(p5.Element.prototype); /** * Resize our canvas element. */ p5.Renderer.prototype.resize = function(w, h) { this.width = w; this.height = h; this.elt.width = w * this._pInst._pixelDensity; this.elt.height = h * this._pInst._pixelDensity; this.elt.style.width = w +'px'; this.elt.style.height = h + 'px'; if (this._isMainCanvas) { this._pInst._setProperty('width', this.width); this._pInst._setProperty('height', this.height); } }; p5.Renderer.prototype.textLeading = function(l) { if (arguments.length && arguments[0]) { this._setProperty('_textLeading', l); return this; } return this._textLeading; }; p5.Renderer.prototype.textSize = function(s) { if (arguments.length && arguments[0]) { this._setProperty('_textSize', s); this._setProperty('_textLeading', s * constants._DEFAULT_LEADMULT); return this._applyTextProperties(); } return this._textSize; }; p5.Renderer.prototype.textStyle = function(s) { if (arguments.length && arguments[0]) { if (s === constants.NORMAL || s === constants.ITALIC || s === constants.BOLD) { this._setProperty('_textStyle', s); } return this._applyTextProperties(); } return this._textStyle; }; p5.Renderer.prototype.textAscent = function() { if (this._textAscent === null) { this._updateTextMetrics(); } return this._textAscent; }; p5.Renderer.prototype.textDescent = function() { if (this._textDescent === null) { this._updateTextMetrics(); } return this._textDescent; }; p5.Renderer.prototype._applyDefaults = function(){ return this; }; /** * Helper fxn to check font type (system or otf) */ p5.Renderer.prototype._isOpenType = function(f) { f = f || this._textFont; return (typeof f === 'object' && f.font && f.font.supported); }; p5.Renderer.prototype._updateTextMetrics = function() { if (this._isOpenType()) { this._setProperty('_textAscent', this._textFont._textAscent()); this._setProperty('_textDescent', this._textFont._textDescent()); return this; } // Adapted from http://stackoverflow.com/a/25355178 var text = document.createElement('span'); text.style.fontFamily = this._textFont; text.style.fontSize = this._textSize + 'px'; text.innerHTML = 'ABCjgq|'; var block = document.createElement('div'); block.style.display = 'inline-block'; block.style.width = '1px'; block.style.height = '0px'; var container = document.createElement('div'); container.appendChild(text); container.appendChild(block); container.style.height = '0px'; container.style.overflow = 'hidden'; document.body.appendChild(container); block.style.verticalAlign = 'baseline'; var blockOffset = calculateOffset(block); var textOffset = calculateOffset(text); var ascent = blockOffset[1] - textOffset[1]; block.style.verticalAlign = 'bottom'; blockOffset = calculateOffset(block); textOffset = calculateOffset(text); var height = blockOffset[1] - textOffset[1]; var descent = height - ascent; document.body.removeChild(container); this._setProperty('_textAscent', ascent); this._setProperty('_textDescent', descent); return this; }; /** * Helper fxn to measure ascent and descent. * Adapted from http://stackoverflow.com/a/25355178 */ function calculateOffset(object) { var currentLeft = 0, currentTop = 0; if (object.offsetParent) { do { currentLeft += object.offsetLeft; currentTop += object.offsetTop; } while (object = object.offsetParent); } else { currentLeft += object.offsetLeft; currentTop += object.offsetTop; } return [currentLeft, currentTop]; } module.exports = p5.Renderer; },{"../core/constants":4,"./core":5}],13:[function(_dereq_,module,exports){ var p5 = _dereq_('./core'); var canvas = _dereq_('./canvas'); var constants = _dereq_('./constants'); var filters = _dereq_('../image/filters'); _dereq_('./p5.Renderer'); /** * p5.Renderer2D * The 2D graphics canvas renderer class. * extends p5.Renderer */ var styleEmpty = 'rgba(0,0,0,0)'; // var alphaThreshold = 0.00125; // minimum visible p5.Renderer2D = function(elt, pInst, isMainCanvas){ p5.Renderer.call(this, elt, pInst, isMainCanvas); this.drawingContext = this.canvas.getContext('2d'); this._pInst._setProperty('drawingContext', this.drawingContext); return this; }; p5.Renderer2D.prototype = Object.create(p5.Renderer.prototype); p5.Renderer2D.prototype._applyDefaults = function() { this._setFill(constants._DEFAULT_FILL); this._setStroke(constants._DEFAULT_STROKE); this.drawingContext.lineCap = constants.ROUND; this.drawingContext.font = 'normal 12px sans-serif'; }; p5.Renderer2D.prototype.resize = function(w,h) { p5.Renderer.prototype.resize.call(this, w,h); this.drawingContext.scale(this._pInst._pixelDensity, this._pInst._pixelDensity); }; ////////////////////////////////////////////// // COLOR | Setting ////////////////////////////////////////////// p5.Renderer2D.prototype.background = function() { this.drawingContext.save(); this.drawingContext.setTransform(1, 0, 0, 1, 0, 0); this.drawingContext.scale(this._pInst._pixelDensity, this._pInst._pixelDensity); if (arguments[0] instanceof p5.Image) { this._pInst.image(arguments[0], 0, 0, this.width, this.height); } else { var curFill = this._getFill(); // create background rect var color = this._pInst.color.apply(this, arguments); var newFill = color.toString(); this._setFill(newFill); this.drawingContext.fillRect(0, 0, this.width, this.height); // reset fill this._setFill(curFill); } this.drawingContext.restore(); }; p5.Renderer2D.prototype.clear = function() { this.drawingContext.clearRect(0, 0, this.width, this.height); }; p5.Renderer2D.prototype.fill = function() { var color = this._pInst.color.apply(this, arguments); this._setFill(color.toString()); }; p5.Renderer2D.prototype.stroke = function() { var color = this._pInst.color.apply(this, arguments); this._setStroke(color.toString()); }; ////////////////////////////////////////////// // IMAGE | Loading & Displaying ////////////////////////////////////////////// p5.Renderer2D.prototype.image = function (img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) { var cnv; try { if (this._tint) { if (p5.MediaElement && img instanceof p5.MediaElement) { img.loadPixels(); } if (img.canvas) { cnv = this._getTintedImageCanvas(img); } } if (!cnv) { cnv = img.canvas || img.elt; } this.drawingContext.drawImage(cnv, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); } catch (e) { if (e.name !== 'NS_ERROR_NOT_AVAILABLE') { throw e; } } }; p5.Renderer2D.prototype._getTintedImageCanvas = function (img) { if (!img.canvas) { return img; } var pixels = filters._toPixels(img.canvas); var tmpCanvas = document.createElement('canvas'); tmpCanvas.width = img.canvas.width; tmpCanvas.height = img.canvas.height; var tmpCtx = tmpCanvas.getContext('2d'); var id = tmpCtx.createImageData(img.canvas.width, img.canvas.height); var newPixels = id.data; for (var i = 0; i < pixels.length; i += 4) { var r = pixels[i]; var g = pixels[i + 1]; var b = pixels[i + 2]; var a = pixels[i + 3]; newPixels[i] = r * this._tint[0] / 255; newPixels[i + 1] = g * this._tint[1] / 255; newPixels[i + 2] = b * this._tint[2] / 255; newPixels[i + 3] = a * this._tint[3] / 255; } tmpCtx.putImageData(id, 0, 0); return tmpCanvas; }; ////////////////////////////////////////////// // IMAGE | Pixels ////////////////////////////////////////////// p5.Renderer2D.prototype.blendMode = function(mode) { this.drawingContext.globalCompositeOperation = mode; }; p5.Renderer2D.prototype.blend = function() { var currBlend = this.drawingContext.globalCompositeOperation; var blendMode = arguments[arguments.length - 1]; var copyArgs = Array.prototype.slice.call( arguments, 0, arguments.length - 1 ); this.drawingContext.globalCompositeOperation = blendMode; if (this._pInst) { this._pInst.copy.apply(this._pInst, copyArgs); } else { this.copy.apply(this, copyArgs); } this.drawingContext.globalCompositeOperation = currBlend; }; p5.Renderer2D.prototype.copy = function () { var srcImage, sx, sy, sw, sh, dx, dy, dw, dh; if (arguments.length === 9) { srcImage = arguments[0]; sx = arguments[1]; sy = arguments[2]; sw = arguments[3]; sh = arguments[4]; dx = arguments[5]; dy = arguments[6]; dw = arguments[7]; dh = arguments[8]; } else if (arguments.length === 8) { srcImage = this._pInst; sx = arguments[0]; sy = arguments[1]; sw = arguments[2]; sh = arguments[3]; dx = arguments[4]; dy = arguments[5]; dw = arguments[6]; dh = arguments[7]; } else { throw new Error('Signature not supported'); } p5.Renderer2D._copyHelper(srcImage, sx, sy, sw, sh, dx, dy, dw, dh); }; p5.Renderer2D._copyHelper = function (srcImage, sx, sy, sw, sh, dx, dy, dw, dh) { srcImage.loadPixels(); var s = srcImage.canvas.width / srcImage.width; this.drawingContext.drawImage(srcImage.canvas, s * sx, s * sy, s * sw, s * sh, dx, dy, dw, dh); }; p5.Renderer2D.prototype.get = function(x, y, w, h) { if (x === undefined && y === undefined && w === undefined && h === undefined){ x = 0; y = 0; w = this.width; h = this.height; } else if (w === undefined && h === undefined) { w = 1; h = 1; } // if the section does not overlap the canvas if(x + w < 0 || y + h < 0 || x > this.width || y > this.height){ return [0, 0, 0, 255]; } var ctx = this._pInst || this; ctx.loadPixels(); var pd = ctx._pixelDensity; // round down to get integer numbers x = Math.floor(x); y = Math.floor(y); w = Math.floor(w); h = Math.floor(h); var sx = x * pd; var sy = y * pd; if (w === 1 && h === 1){ var imageData = this.drawingContext.getImageData(sx, sy, 1, 1).data; //imageData = [0,0,0,0]; return [ imageData[0], imageData[1], imageData[2], imageData[3] ]; } else { //auto constrain the width and height to //dimensions of the source image var dw = Math.min(w, ctx.width); var dh = Math.min(h, ctx.height); var sw = dw * pd; var sh = dh * pd; var region = new p5.Image(dw, dh); region.canvas.getContext('2d').drawImage(this.canvas, sx, sy, sw, sh, 0, 0, dw, dh); return region; } }; p5.Renderer2D.prototype.loadPixels = function () { var pd = this._pixelDensity || this._pInst._pixelDensity; var w = this.width * pd; var h = this.height * pd; var imageData = this.drawingContext.getImageData(0, 0, w, h); // @todo this should actually set pixels per object, so diff buffers can // have diff pixel arrays. if (this._pInst) { this._pInst._setProperty('imageData', imageData); this._pInst._setProperty('pixels', imageData.data); } else { // if called by p5.Image this._setProperty('imageData', imageData); this._setProperty('pixels', imageData.data); } }; p5.Renderer2D.prototype.set = function (x, y, imgOrCol) { // round down to get integer numbers x = Math.floor(x); y = Math.floor(y); if (imgOrCol instanceof p5.Image) { this.drawingContext.save(); this.drawingContext.setTransform(1, 0, 0, 1, 0, 0); this.drawingContext.scale(this._pInst._pixelDensity, this._pInst._pixelDensity); this.drawingContext.drawImage(imgOrCol.canvas, x, y); this.loadPixels.call(this._pInst); this.drawingContext.restore(); } else { var ctx = this._pInst || this; var r = 0, g = 0, b = 0, a = 0; var idx = 4*((y * ctx._pixelDensity) * (this.width * ctx._pixelDensity) + (x * ctx._pixelDensity)); if (!ctx.imageData) { ctx.loadPixels.call(ctx); } if (typeof imgOrCol === 'number') { if (idx < ctx.pixels.length) { r = imgOrCol; g = imgOrCol; b = imgOrCol; a = 255; //this.updatePixels.call(this); } } else if (imgOrCol instanceof Array) { if (imgOrCol.length < 4) { throw new Error('pixel array must be of the form [R, G, B, A]'); } if (idx < ctx.pixels.length) { r = imgOrCol[0]; g = imgOrCol[1]; b = imgOrCol[2]; a = imgOrCol[3]; //this.updatePixels.call(this); } } else if (imgOrCol instanceof p5.Color) { if (idx < ctx.pixels.length) { r = imgOrCol.levels[0]; g = imgOrCol.levels[1]; b = imgOrCol.levels[2]; a = imgOrCol.levels[3]; //this.updatePixels.call(this); } } // loop over pixelDensity * pixelDensity for (var i = 0; i < ctx._pixelDensity; i++) { for (var j = 0; j < ctx._pixelDensity; j++) { // loop over idx = 4*((y * ctx._pixelDensity + j) * this.width * ctx._pixelDensity + (x * ctx._pixelDensity + i)); ctx.pixels[idx] = r; ctx.pixels[idx+1] = g; ctx.pixels[idx+2] = b; ctx.pixels[idx+3] = a; } } } }; p5.Renderer2D.prototype.updatePixels = function (x, y, w, h) { var pd = this._pixelDensity || this._pInst._pixelDensity; if (x === undefined && y === undefined && w === undefined && h === undefined) { x = 0; y = 0; w = this.width; h = this.height; } w *= pd; h *= pd; if (this._pInst) { this.drawingContext.putImageData(this._pInst.imageData, x, y, 0, 0, w, h); } else { this.drawingContext.putImageData(this.imageData, x, y, 0, 0, w, h); } }; ////////////////////////////////////////////// // SHAPE | 2D Primitives ////////////////////////////////////////////// /** * Generate a cubic Bezier representing an arc on the unit circle of total * angle `size` radians, beginning `start` radians above the x-axis. Up to * four of these curves are combined to make a full arc. * * See www.joecridge.me/bezier.pdf for an explanation of the method. */ p5.Renderer2D.prototype._acuteArcToBezier = function _acuteArcToBezier(start, size) { // Evauate constants. var alpha = size / 2.0, cos_alpha = Math.cos(alpha), sin_alpha = Math.sin(alpha), cot_alpha = 1.0 / Math.tan(alpha), phi = start + alpha, // This is how far the arc needs to be rotated. cos_phi = Math.cos(phi), sin_phi = Math.sin(phi), lambda = (4.0 - cos_alpha) / 3.0, mu = sin_alpha + (cos_alpha - lambda) * cot_alpha; // Return rotated waypoints. return { ax: Math.cos(start), ay: Math.sin(start), bx: lambda * cos_phi + mu * sin_phi, by: lambda * sin_phi - mu * cos_phi, cx: lambda * cos_phi - mu * sin_phi, cy: lambda * sin_phi + mu * cos_phi, dx: Math.cos(start + size), dy: Math.sin(start + size) }; }; p5.Renderer2D.prototype.arc = function(x, y, w, h, start, stop, mode) { var ctx = this.drawingContext; var vals = canvas.arcModeAdjust(x, y, w, h, this._ellipseMode); var rx = vals.w / 2.0; var ry = vals.h / 2.0; var epsilon = 0.00001; // Smallest visible angle on displays up to 4K. var arcToDraw = 0; var curves = []; // Create curves while(stop - start > epsilon) { arcToDraw = Math.min(stop - start, constants.HALF_PI); curves.push(this._acuteArcToBezier(start, arcToDraw)); start += arcToDraw; } // Fill curves if (this._doFill) { ctx.beginPath(); curves.forEach(function (curve, index) { if (index === 0) { ctx.moveTo(vals.x + curve.ax * rx, vals.y + curve.ay * ry); } ctx.bezierCurveTo(vals.x + curve.bx * rx, vals.y + curve.by * ry, vals.x + curve.cx * rx, vals.y + curve.cy * ry, vals.x + curve.dx * rx, vals.y + curve.dy * ry); }); if (mode === constants.PIE || mode == null) { ctx.lineTo(vals.x, vals.y); } ctx.closePath(); ctx.fill(); } // Stroke curves if (this._doStroke) { ctx.beginPath(); curves.forEach(function (curve, index) { if (index === 0) { ctx.moveTo(vals.x + curve.ax * rx, vals.y + curve.ay * ry); } ctx.bezierCurveTo(vals.x + curve.bx * rx, vals.y + curve.by * ry, vals.x + curve.cx * rx, vals.y + curve.cy * ry, vals.x + curve.dx * rx, vals.y + curve.dy * ry); }); if (mode === constants.PIE) { ctx.lineTo(vals.x, vals.y); ctx.closePath(); } else if (mode === constants.CHORD) { ctx.closePath(); } ctx.stroke(); } return this; }; p5.Renderer2D.prototype.ellipse = function(args) { var ctx = this.drawingContext; var doFill = this._doFill, doStroke = this._doStroke; var x = args[0], y = args[1], w = args[2], h = args[3]; if (doFill && !doStroke) { if(this._getFill() === styleEmpty) { return this; } } else if (!doFill && doStroke) { if(this._getStroke() === styleEmpty) { return this; } } var kappa = 0.5522847498, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical xe = x + w, // x-end ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle ctx.beginPath(); ctx.moveTo(x, ym); ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); ctx.closePath(); if (doFill) { ctx.fill(); } if (doStroke) { ctx.stroke(); } }; p5.Renderer2D.prototype.line = function(x1, y1, x2, y2) { var ctx = this.drawingContext; if (!this._doStroke) { return this; } else if(this._getStroke() === styleEmpty){ return this; } // Translate the line by (0.5, 0.5) to draw it crisp if (ctx.lineWidth % 2 === 1) { ctx.translate(0.5, 0.5); } ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); if (ctx.lineWidth % 2 === 1) { ctx.translate(-0.5, -0.5); } return this; }; p5.Renderer2D.prototype.point = function(x, y) { var ctx = this.drawingContext; if (!this._doStroke) { return this; } else if(this._getStroke() === styleEmpty){ return this; } x = Math.round(x); y = Math.round(y); if (ctx.lineWidth > 1) { ctx.beginPath(); ctx.arc( x, y, ctx.lineWidth / 2, 0, constants.TWO_PI, false ); ctx.fill(); } else { ctx.fillRect(x, y, 1, 1); } }; p5.Renderer2D.prototype.quad = function(x1, y1, x2, y2, x3, y3, x4, y4) { var ctx = this.drawingContext; var doFill = this._doFill, doStroke = this._doStroke; if (doFill && !doStroke) { if(this._getFill() === styleEmpty) { return this; } } else if (!doFill && doStroke) { if(this._getStroke() === styleEmpty) { return this; } } ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.lineTo(x3, y3); ctx.lineTo(x4, y4); ctx.closePath(); if (doFill) { ctx.fill(); } if (doStroke) { ctx.stroke(); } return this; }; p5.Renderer2D.prototype.rect = function(args) { var x = args[0], y = args[1], w = args[2], h = args[3], tl = args[4], tr = args[5], br = args[6], bl = args[7]; var ctx = this.drawingContext; var doFill = this._doFill, doStroke = this._doStroke; if (doFill && !doStroke) { if(this._getFill() === styleEmpty) { return this; } } else if (!doFill && doStroke) { if(this._getStroke() === styleEmpty) { return this; } } // Translate the line by (0.5, 0.5) to draw a crisp rectangle border if (this._doStroke && ctx.lineWidth % 2 === 1) { ctx.translate(0.5, 0.5); } ctx.beginPath(); if (typeof tl === 'undefined') { // No rounded corners ctx.rect(x, y, w, h); } else { // At least one rounded corner // Set defaults when not specified if (typeof tr === 'undefined') { tr = tl; } if (typeof br === 'undefined') { br = tr; } if (typeof bl === 'undefined') { bl = br; } var hw = w / 2; var hh = h / 2; // Clip radii if (w < 2 * tl) { tl = hw; } if (h < 2 * tl) { tl = hh; } if (w < 2 * tr) { tr = hw; } if (h < 2 * tr) { tr = hh; } if (w < 2 * br) { br = hw; } if (h < 2 * br) { br = hh; } if (w < 2 * bl) { bl = hw; } if (h < 2 * bl) { bl = hh; } // Draw shape ctx.beginPath(); ctx.moveTo(x + tl, y); ctx.arcTo(x + w, y, x + w, y + h, tr); ctx.arcTo(x + w, y + h, x, y + h, br); ctx.arcTo(x, y + h, x, y, bl); ctx.arcTo(x, y, x + w, y, tl); ctx.closePath(); } if (this._doFill) { ctx.fill(); } if (this._doStroke) { ctx.stroke(); } if (this._doStroke && ctx.lineWidth % 2 === 1) { ctx.translate(-0.5, -0.5); } return this; }; p5.Renderer2D.prototype.triangle = function(args) { var ctx = this.drawingContext; var doFill = this._doFill, doStroke = this._doStroke; var x1=args[0], y1=args[1]; var x2=args[2], y2=args[3]; var x3=args[4], y3=args[5]; if (doFill && !doStroke) { if(this._getFill() === styleEmpty) { return this; } } else if (!doFill && doStroke) { if(this._getStroke() === styleEmpty) { return this; } } ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.lineTo(x3, y3); ctx.closePath(); if (doFill) { ctx.fill(); } if (doStroke) { ctx.stroke(); } }; p5.Renderer2D.prototype.endShape = function (mode, vertices, isCurve, isBezier, isQuadratic, isContour, shapeKind) { if (vertices.length === 0) { return this; } if (!this._doStroke && !this._doFill) { return this; } var closeShape = mode === constants.CLOSE; var v; if (closeShape && !isContour) { vertices.push(vertices[0]); } var i, j; var numVerts = vertices.length; if (isCurve && (shapeKind === constants.POLYGON || shapeKind === null)) { if (numVerts > 3) { var b = [], s = 1 - this._curveTightness; this.drawingContext.beginPath(); this.drawingContext.moveTo(vertices[1][0], vertices[1][1]); for (i = 1; i + 2 < numVerts; i++) { v = vertices[i]; b[0] = [ v[0], v[1] ]; b[1] = [ v[0] + (s * vertices[i + 1][0] - s * vertices[i - 1][0]) / 6, v[1] + (s * vertices[i + 1][1] - s * vertices[i - 1][1]) / 6 ]; b[2] = [ vertices[i + 1][0] + (s * vertices[i][0]-s * vertices[i + 2][0]) / 6, vertices[i + 1][1]+(s * vertices[i][1] - s*vertices[i + 2][1]) / 6 ]; b[3] = [ vertices[i + 1][0], vertices[i + 1][1] ]; this.drawingContext.bezierCurveTo(b[1][0],b[1][1], b[2][0],b[2][1],b[3][0],b[3][1]); } if (closeShape) { this.drawingContext.lineTo(vertices[i + 1][0], vertices[i + 1][1]); } this._doFillStrokeClose(); } } else if (isBezier&&(shapeKind===constants.POLYGON ||shapeKind === null)) { this.drawingContext.beginPath(); for (i = 0; i < numVerts; i++) { if (vertices[i].isVert) { if (vertices[i].moveTo) { this.drawingContext.moveTo(vertices[i][0], vertices[i][1]); } else { this.drawingContext.lineTo(vertices[i][0], vertices[i][1]); } } else { this.drawingContext.bezierCurveTo(vertices[i][0], vertices[i][1], vertices[i][2], vertices[i][3], vertices[i][4], vertices[i][5]); } } this._doFillStrokeClose(); } else if (isQuadratic && (shapeKind === constants.POLYGON || shapeKind === null)) { this.drawingContext.beginPath(); for (i = 0; i < numVerts; i++) { if (vertices[i].isVert) { if (vertices[i].moveTo) { this.drawingContext.moveTo([0], vertices[i][1]); } else { this.drawingContext.lineTo(vertices[i][0], vertices[i][1]); } } else { this.drawingContext.quadraticCurveTo(vertices[i][0], vertices[i][1], vertices[i][2], vertices[i][3]); } } this._doFillStrokeClose(); } else { if (shapeKind === constants.POINTS) { for (i = 0; i < numVerts; i++) { v = vertices[i]; if (this._doStroke) { this._pInst.stroke(v[6]); } this._pInst.point(v[0], v[1]); } } else if (shapeKind === constants.LINES) { for (i = 0; i + 1 < numVerts; i += 2) { v = vertices[i]; if (this._doStroke) { this._pInst.stroke(vertices[i + 1][6]); } this._pInst.line(v[0], v[1], vertices[i + 1][0], vertices[i + 1][1]); } } else if (shapeKind === constants.TRIANGLES) { for (i = 0; i + 2 < numVerts; i += 3) { v = vertices[i]; this.drawingContext.beginPath(); this.drawingContext.moveTo(v[0], v[1]); this.drawingContext.lineTo(vertices[i + 1][0], vertices[i + 1][1]); this.drawingContext.lineTo(vertices[i + 2][0], vertices[i + 2][1]); this.drawingContext.lineTo(v[0], v[1]); if (this._doFill) { this._pInst.fill(vertices[i + 2][5]); this.drawingContext.fill(); } if (this._doStroke) { this._pInst.stroke(vertices[i + 2][6]); this.drawingContext.stroke(); } this.drawingContext.closePath(); } } else if (shapeKind === constants.TRIANGLE_STRIP) { for (i = 0; i + 1 < numVerts; i++) { v = vertices[i]; this.drawingContext.beginPath(); this.drawingContext.moveTo(vertices[i + 1][0], vertices[i + 1][1]); this.drawingContext.lineTo(v[0], v[1]); if (this._doStroke) { this._pInst.stroke(vertices[i + 1][6]); } if (this._doFill) { this._pInst.fill(vertices[i + 1][5]); } if (i + 2 < numVerts) { this.drawingContext.lineTo(vertices[i + 2][0], vertices[i + 2][1]); if (this._doStroke) { this._pInst.stroke(vertices[i + 2][6]); } if (this._doFill) { this._pInst.fill(vertices[i + 2][5]); } } this._doFillStrokeClose(); } } else if (shapeKind === constants.TRIANGLE_FAN) { if (numVerts > 2) { // For performance reasons, try to batch as many of the // fill and stroke calls as possible. this.drawingContext.beginPath(); for (i = 2; i < numVerts; i++) { v = vertices[i]; this.drawingContext.moveTo(vertices[0][0], vertices[0][1]); this.drawingContext.lineTo(vertices[i - 1][0], vertices[i - 1][1]); this.drawingContext.lineTo(v[0], v[1]); this.drawingContext.lineTo(vertices[0][0], vertices[0][1]); // If the next colour is going to be different, stroke / fill now if (i < numVerts - 1) { if ( (this._doFill && v[5] !== vertices[i + 1][5]) || (this._doStroke && v[6] !== vertices[i + 1][6])) { if (this._doFill) { this._pInst.fill(v[5]); this.drawingContext.fill(); this._pInst.fill(vertices[i + 1][5]); } if (this._doStroke) { this._pInst.stroke(v[6]); this.drawingContext.stroke(); this._pInst.stroke(vertices[i + 1][6]); } this.drawingContext.closePath(); this.drawingContext.beginPath(); // Begin the next one } } } this._doFillStrokeClose(); } } else if (shapeKind === constants.QUADS) { for (i = 0; i + 3 < numVerts; i += 4) { v = vertices[i]; this.drawingContext.beginPath(); this.drawingContext.moveTo(v[0], v[1]); for (j = 1; j < 4; j++) { this.drawingContext.lineTo(vertices[i + j][0], vertices[i + j][1]); } this.drawingContext.lineTo(v[0], v[1]); if (this._doFill) { this._pInst.fill(vertices[i + 3][5]); } if (this._doStroke) { this._pInst.stroke(vertices[i + 3][6]); } this._doFillStrokeClose(); } } else if (shapeKind === constants.QUAD_STRIP) { if (numVerts > 3) { for (i = 0; i + 1 < numVerts; i += 2) { v = vertices[i]; this.drawingContext.beginPath(); if (i + 3 < numVerts) { this.drawingContext.moveTo(vertices[i + 2][0], vertices[i+2][1]); this.drawingContext.lineTo(v[0], v[1]); this.drawingContext.lineTo(vertices[i + 1][0], vertices[i+1][1]); this.drawingContext.lineTo(vertices[i + 3][0], vertices[i+3][1]); if (this._doFill) { this._pInst.fill(vertices[i + 3][5]); } if (this._doStroke) { this._pInst.stroke(vertices[i + 3][6]); } } else { this.drawingContext.moveTo(v[0], v[1]); this.drawingContext.lineTo(vertices[i + 1][0], vertices[i+1][1]); } this._doFillStrokeClose(); } } } else { this.drawingContext.beginPath(); this.drawingContext.moveTo(vertices[0][0], vertices[0][1]); for (i = 1; i < numVerts; i++) { v = vertices[i]; if (v.isVert) { if (v.moveTo) { this.drawingContext.moveTo(v[0], v[1]); } else { this.drawingContext.lineTo(v[0], v[1]); } } } this._doFillStrokeClose(); } } isCurve = false; isBezier = false; isQuadratic = false; isContour = false; if (closeShape) { vertices.pop(); } return this; }; ////////////////////////////////////////////// // SHAPE | Attributes ////////////////////////////////////////////// p5.Renderer2D.prototype.noSmooth = function() { if ('imageSmoothingEnabled' in this.drawingContext) { this.drawingContext.imageSmoothingEnabled = false; } else if ('mozImageSmoothingEnabled' in this.drawingContext) { this.drawingContext.mozImageSmoothingEnabled = false; } else if ('webkitImageSmoothingEnabled' in this.drawingContext) { this.drawingContext.webkitImageSmoothingEnabled = false; } else if ('msImageSmoothingEnabled' in this.drawingContext) { this.drawingContext.msImageSmoothingEnabled = false; } return this; }; p5.Renderer2D.prototype.smooth = function() { if ('imageSmoothingEnabled' in this.drawingContext) { this.drawingContext.imageSmoothingEnabled = true; } else if ('mozImageSmoothingEnabled' in this.drawingContext) { this.drawingContext.mozImageSmoothingEnabled = true; } else if ('webkitImageSmoothingEnabled' in this.drawingContext) { this.drawingContext.webkitImageSmoothingEnabled = true; } else if ('msImageSmoothingEnabled' in this.drawingContext) { this.drawingContext.msImageSmoothingEnabled = true; } return this; }; p5.Renderer2D.prototype.strokeCap = function(cap) { if (cap === constants.ROUND || cap === constants.SQUARE || cap === constants.PROJECT) { this.drawingContext.lineCap = cap; } return this; }; p5.Renderer2D.prototype.strokeJoin = function(join) { if (join === constants.ROUND || join === constants.BEVEL || join === constants.MITER) { this.drawingContext.lineJoin = join; } return this; }; p5.Renderer2D.prototype.strokeWeight = function(w) { if (typeof w === 'undefined' || w === 0) { // hack because lineWidth 0 doesn't work this.drawingContext.lineWidth = 0.0001; } else { this.drawingContext.lineWidth = w; } return this; }; p5.Renderer2D.prototype._getFill = function(){ return this._cachedFillStyle; }; p5.Renderer2D.prototype._setFill = function(fillStyle){ if (fillStyle !== this._cachedFillStyle) { this.drawingContext.fillStyle = fillStyle; this._cachedFillStyle = fillStyle; } }; p5.Renderer2D.prototype._getStroke = function(){ return this._cachedStrokeStyle; }; p5.Renderer2D.prototype._setStroke = function(strokeStyle){ if (strokeStyle !== this._cachedStrokeStyle) { this.drawingContext.strokeStyle = strokeStyle; this._cachedStrokeStyle = strokeStyle; } }; ////////////////////////////////////////////// // SHAPE | Curves ////////////////////////////////////////////// p5.Renderer2D.prototype.bezier = function (x1, y1, x2, y2, x3, y3, x4, y4) { this._pInst.beginShape(); this._pInst.vertex(x1, y1); this._pInst.bezierVertex(x2, y2, x3, y3, x4, y4); this._pInst.endShape(); return this; }; p5.Renderer2D.prototype.curve = function (x1, y1, x2, y2, x3, y3, x4, y4) { this._pInst.beginShape(); this._pInst.curveVertex(x1, y1); this._pInst.curveVertex(x2, y2); this._pInst.curveVertex(x3, y3); this._pInst.curveVertex(x4, y4); this._pInst.endShape(); return this; }; ////////////////////////////////////////////// // SHAPE | Vertex ////////////////////////////////////////////// p5.Renderer2D.prototype._doFillStrokeClose = function () { if (this._doFill) { this.drawingContext.fill(); } if (this._doStroke) { this.drawingContext.stroke(); } this.drawingContext.closePath(); }; ////////////////////////////////////////////// // TRANSFORM ////////////////////////////////////////////// p5.Renderer2D.prototype.applyMatrix = function(n00, n01, n02, n10, n11, n12) { this.drawingContext.transform(n00, n01, n02, n10, n11, n12); }; p5.Renderer2D.prototype.resetMatrix = function() { this.drawingContext.setTransform(1, 0, 0, 1, 0, 0); this.drawingContext.scale(this._pInst._pixelDensity, this._pInst._pixelDensity); return this; }; p5.Renderer2D.prototype.rotate = function(r) { this.drawingContext.rotate(r); }; p5.Renderer2D.prototype.scale = function(x,y) { this.drawingContext.scale(x, y); return this; }; p5.Renderer2D.prototype.shearX = function(angle) { if (this._pInst._angleMode === constants.DEGREES) { // undoing here, because it gets redone in tan() angle = this._pInst.degrees(angle); } this.drawingContext.transform(1, 0, this._pInst.tan(angle), 1, 0, 0); return this; }; p5.Renderer2D.prototype.shearY = function(angle) { if (this._pInst._angleMode === constants.DEGREES) { // undoing here, because it gets redone in tan() angle = this._pInst.degrees(angle); } this.drawingContext.transform(1, this._pInst.tan(angle), 0, 1, 0, 0); return this; }; p5.Renderer2D.prototype.translate = function(x, y) { this.drawingContext.translate(x, y); return this; }; ////////////////////////////////////////////// // TYPOGRAPHY // ////////////////////////////////////////////// p5.Renderer2D.prototype.text = function (str, x, y, maxWidth, maxHeight) { var p = this._pInst, cars, n, ii, jj, line, testLine, testWidth, words, totalHeight, baselineHacked, finalMaxHeight = Number.MAX_VALUE; // baselineHacked: (HACK) // A temporary fix to conform to Processing's implementation // of BASELINE vertical alignment in a bounding box if (!(this._doFill || this._doStroke)) { return; } if (typeof str !== 'string') { str = str.toString(); } str = str.replace(/(\t)/g, ' '); cars = str.split('\n'); if (typeof maxWidth !== 'undefined') { totalHeight = 0; for (ii = 0; ii < cars.length; ii++) { line = ''; words = cars[ii].split(' '); for (n = 0; n < words.length; n++) { testLine = line + words[n] + ' '; testWidth = this.textWidth(testLine); if (testWidth > maxWidth) { line = words[n] + ' '; totalHeight += p.textLeading(); } else { line = testLine; } } } if (this._rectMode === constants.CENTER) { x -= maxWidth / 2; y -= maxHeight / 2; } switch (this.drawingContext.textAlign) { case constants.CENTER: x += maxWidth / 2; break; case constants.RIGHT: x += maxWidth; break; } if (typeof maxHeight !== 'undefined') { switch (this.drawingContext.textBaseline) { case constants.BOTTOM: y += (maxHeight - totalHeight); break; case constants._CTX_MIDDLE: // CENTER? y += (maxHeight - totalHeight) / 2; break; case constants.BASELINE: baselineHacked = true; this.drawingContext.textBaseline = constants.TOP; break; } // remember the max-allowed y-position for any line (fix to #928) finalMaxHeight = (y + maxHeight) - p.textAscent(); } for (ii = 0; ii < cars.length; ii++) { line = ''; words = cars[ii].split(' '); for (n = 0; n < words.length; n++) { testLine = line + words[n] + ' '; testWidth = this.textWidth(testLine); if (testWidth > maxWidth && line.length > 0) { this._renderText(p, line, x, y, finalMaxHeight); line = words[n] + ' '; y += p.textLeading(); } else { line = testLine; } } this._renderText(p, line, x, y, finalMaxHeight); y += p.textLeading(); } } else { // Offset to account for vertically centering multiple lines of text - no // need to adjust anything for vertical align top or baseline var offset = 0, vAlign = p.textAlign().vertical; if (vAlign === constants.CENTER) { offset = ((cars.length - 1) * p.textLeading()) / 2; } else if (vAlign === constants.BOTTOM) { offset = (cars.length - 1) * p.textLeading(); } for (jj = 0; jj < cars.length; jj++) { this._renderText(p, cars[jj], x, y-offset, finalMaxHeight); y += p.textLeading(); } } if (baselineHacked) { this.drawingContext.textBaseline = constants.BASELINE; } return p; }; p5.Renderer2D.prototype._renderText = function(p, line, x, y, maxY) { if (y >= maxY) { return; // don't render lines beyond our maxY position } p.push(); // fix to #803 if (!this._isOpenType()) { // a system/browser font // no stroke unless specified by user if (this._doStroke && this._strokeSet) { this.drawingContext.strokeText(line, x, y); } if (this._doFill) { // if fill hasn't been set by user, use default text fill if (! this._fillSet) { this._setFill(constants._DEFAULT_TEXT_FILL); } this.drawingContext.fillText(line, x, y); } } else { // an opentype font, let it handle the rendering this._textFont._renderPath(line, x, y, { renderer: this }); } p.pop(); return p; }; p5.Renderer2D.prototype.textWidth = function(s) { if (this._isOpenType()) { return this._textFont._textWidth(s, this._textSize); } return this.drawingContext.measureText(s).width; }; p5.Renderer2D.prototype.textAlign = function(h, v) { if (arguments.length) { if (h === constants.LEFT || h === constants.RIGHT || h === constants.CENTER) { this.drawingContext.textAlign = h; } if (v === constants.TOP || v === constants.BOTTOM || v === constants.CENTER || v === constants.BASELINE) { if (v === constants.CENTER) { this.drawingContext.textBaseline = constants._CTX_MIDDLE; } else { this.drawingContext.textBaseline = v; } } return this._pInst; } else { var valign = this.drawingContext.textBaseline; if (valign === constants._CTX_MIDDLE) { valign = constants.CENTER; } return { horizontal: this.drawingContext.textAlign, vertical: valign }; } }; p5.Renderer2D.prototype._applyTextProperties = function() { var font, p = this._pInst; this._setProperty('_textAscent', null); this._setProperty('_textDescent', null); font = this._textFont; if (this._isOpenType()) { font = this._textFont.font.familyName; this._setProperty('_textStyle', this._textFont.font.styleName); } this.drawingContext.font = this._textStyle + ' ' + this._textSize + 'px ' + font; return p; }; ////////////////////////////////////////////// // STRUCTURE ////////////////////////////////////////////// p5.Renderer2D.prototype.push = function() { this.drawingContext.save(); }; p5.Renderer2D.prototype.pop = function() { this.drawingContext.restore(); // Re-cache the fill / stroke state this._cachedFillStyle = this.drawingContext.fillStyle; this._cachedStrokeStyle = this.drawingContext.strokeStyle; }; module.exports = p5.Renderer2D; },{"../image/filters":19,"./canvas":3,"./constants":4,"./core":5,"./p5.Renderer":12}],14:[function(_dereq_,module,exports){ /** * @module Rendering * @submodule Rendering * @for p5 */ var p5 = _dereq_('./core'); var constants = _dereq_('./constants'); _dereq_('./p5.Graphics'); _dereq_('./p5.Renderer2D'); _dereq_('../webgl/p5.RendererGL'); var defaultId = 'defaultCanvas0'; // this gets set again in createCanvas /** * Creates a canvas element in the document, and sets the dimensions of it * in pixels. This method should be called only once at the start of setup. * Calling createCanvas more than once in a sketch will result in very * unpredicable behavior. If you want more than one drawing canvas * you could use createGraphics (hidden by default but it can be shown). *

* The system variables width and height are set by the parameters passed * to this function. If createCanvas() is not used, the window will be * given a default size of 100x100 pixels. *

* For more ways to position the canvas, see the * * positioning the canvas wiki page. * * @method createCanvas * @param {Number} w width of the canvas * @param {Number} h height of the canvas * @param {Constant} [renderer] either P2D or WEBGL * @return {HTMLCanvasElement} canvas generated * @example *
* * function setup() { * createCanvas(100, 50); * background(153); * line(0, 0, width, height); * } * *
* * @alt * Black line extending from top-left of canvas to bottom right. * */ p5.prototype.createCanvas = function(w, h, renderer) { //optional: renderer, otherwise defaults to p2d var r = renderer || constants.P2D; var isDefault, c; //4th arg (isDefault) used when called onLoad, //otherwise hidden to the public api if(arguments[3]){ isDefault = (typeof arguments[3] === 'boolean') ? arguments[3] : false; } if(r === constants.WEBGL){ c = document.getElementById(defaultId); if(c){ //if defaultCanvas already exists c.parentNode.removeChild(c); //replace the existing defaultCanvas } c = document.createElement('canvas'); c.id = defaultId; } else { if (isDefault) { c = document.createElement('canvas'); var i = 0; while (document.getElementById('defaultCanvas'+i)) { i++; } defaultId = 'defaultCanvas'+i; c.id = defaultId; } else { // resize the default canvas if new one is created c = this.canvas; } } // set to invisible if still in setup (to prevent flashing with manipulate) if (!this._setupDone) { c.dataset.hidden = true; // tag to show later c.style.visibility='hidden'; } if (this._userNode) { // user input node case this._userNode.appendChild(c); } else { document.body.appendChild(c); } // Init our graphics renderer //webgl mode if (r === constants.WEBGL) { this._setProperty('_renderer', new p5.RendererGL(c, this, true)); this._isdefaultGraphics = true; } //P2D mode else { if (!this._isdefaultGraphics) { this._setProperty('_renderer', new p5.Renderer2D(c, this, true)); this._isdefaultGraphics = true; } } this._renderer.resize(w, h); this._renderer._applyDefaults(); if (isDefault) { // only push once this._elements.push(this._renderer); } return this._renderer; }; /** * Resizes the canvas to given width and height. The canvas will be cleared * and draw will be called immediately, allowing the sketch to re-render itself * in the resized canvas. * @method resizeCanvas * @param {Number} w width of the canvas * @param {Number} h height of the canvas * @param {Boolean} noRedraw don't redraw the canvas immediately * @example *
* function setup() { * createCanvas(windowWidth, windowHeight); * } * * function draw() { * background(0, 100, 200); * } * * function windowResized() { * resizeCanvas(windowWidth, windowHeight); * } *
* * @alt * No image displayed. * */ p5.prototype.resizeCanvas = function (w, h, noRedraw) { if (this._renderer) { // save canvas properties var props = {}; for (var key in this.drawingContext) { var val = this.drawingContext[key]; if (typeof val !== 'object' && typeof val !== 'function') { props[key] = val; } } this._renderer.resize(w, h); // reset canvas properties for (var savedKey in props) { this.drawingContext[savedKey] = props[savedKey]; } if (!noRedraw) { this.redraw(); } } }; /** * Removes the default canvas for a p5 sketch that doesn't * require a canvas * @method noCanvas * @example *
* * function setup() { * noCanvas(); * } * *
* * @alt * no image displayed * */ p5.prototype.noCanvas = function() { if (this.canvas) { this.canvas.parentNode.removeChild(this.canvas); } }; /** * Creates and returns a new p5.Renderer object. Use this class if you need * to draw into an off-screen graphics buffer. The two parameters define the * width and height in pixels. * * @method createGraphics * @param {Number} w width of the offscreen graphics buffer * @param {Number} h height of the offscreen graphics buffer * @param {Constant} [renderer] either P2D or WEBGL * undefined defaults to p2d * @return {p5.Graphics} offscreen graphics buffer * @example *
* * var pg; * function setup() { * createCanvas(100, 100); * pg = createGraphics(100, 100); * } * function draw() { * background(200); * pg.background(100); * pg.noStroke(); * pg.ellipse(pg.width/2, pg.height/2, 50, 50); * image(pg, 50, 50); * image(pg, 0, 0, 50, 50); * } * *
* * @alt * 4 grey squares alternating light and dark grey. White quarter circle mid-left. * */ p5.prototype.createGraphics = function(w, h, renderer){ return new p5.Graphics(w, h, renderer, this); }; /** * Blends the pixels in the display window according to the defined mode. * There is a choice of the following modes to blend the source pixels (A) * with the ones of pixels already in the display window (B): *
    *
  • BLEND - linear interpolation of colours: C = * A*factor + B. This is the default blending mode.
  • *
  • ADD - sum of A and B
  • *
  • DARKEST - only the darkest colour succeeds: C = * min(A*factor, B).
  • *
  • LIGHTEST - only the lightest colour succeeds: C = * max(A*factor, B).
  • *
  • DIFFERENCE - subtract colors from underlying image.
  • *
  • EXCLUSION - similar to DIFFERENCE, but less * extreme.
  • *
  • MULTIPLY - multiply the colors, result will always be * darker.
  • *
  • SCREEN - opposite multiply, uses inverse values of the * colors.
  • *
  • REPLACE - the pixels entirely replace the others and * don't utilize alpha (transparency) values.
  • *
  • OVERLAY - mix of MULTIPLY and SCREEN * . Multiplies dark values, and screens light values.
  • *
  • HARD_LIGHT - SCREEN when greater than 50% * gray, MULTIPLY when lower.
  • *
  • SOFT_LIGHT - mix of DARKEST and * LIGHTEST. Works like OVERLAY, but not as harsh. *
  • *
  • DODGE - lightens light tones and increases contrast, * ignores darks.
  • *
  • BURN - darker areas are applied, increasing contrast, * ignores lights.
  • *
* * @method blendMode * @param {Constant} mode blend mode to set for canvas. * either BLEND, DARKEST, LIGHTEST, DIFFERENCE, MULTIPLY, * EXCLUSION, SCREEN, REPLACE, OVERLAY, HARD_LIGHT, * SOFT_LIGHT, DODGE, BURN, ADD or NORMAL * @example *
* * blendMode(LIGHTEST); * strokeWeight(30); * stroke(80, 150, 255); * line(25, 25, 75, 75); * stroke(255, 50, 50); * line(75, 25, 25, 75); * *
*
* * blendMode(MULTIPLY); * strokeWeight(30); * stroke(80, 150, 255); * line(25, 25, 75, 75); * stroke(255, 50, 50); * line(75, 25, 25, 75); * *
* @alt * translucent image thick red & blue diagonal rounded lines intersecting center * Thick red & blue diagonal rounded lines intersecting center. dark at overlap * */ p5.prototype.blendMode = function(mode) { if (mode === constants.BLEND || mode === constants.DARKEST || mode === constants.LIGHTEST || mode === constants.DIFFERENCE || mode === constants.MULTIPLY || mode === constants.EXCLUSION || mode === constants.SCREEN || mode === constants.REPLACE || mode === constants.OVERLAY || mode === constants.HARD_LIGHT || mode === constants.SOFT_LIGHT || mode === constants.DODGE || mode === constants.BURN || mode === constants.ADD || mode === constants.NORMAL) { this._renderer.blendMode(mode); } else { throw new Error('Mode '+mode+' not recognized.'); } }; module.exports = p5; },{"../webgl/p5.RendererGL":28,"./constants":4,"./core":5,"./p5.Graphics":11,"./p5.Renderer2D":13}],15:[function(_dereq_,module,exports){ // requestAnim shim layer by Paul Irish window.requestAnimationFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback, element){ // should '60' here be framerate? window.setTimeout(callback, 1000 / 60); }; })(); // use window.performance() to get max fast and accurate time in milliseconds window.performance = window.performance || {}; window.performance.now = (function(){ var load_date = Date.now(); return window.performance.now || window.performance.mozNow || window.performance.msNow || window.performance.oNow || window.performance.webkitNow || function () { return Date.now() - load_date; }; })(); /* // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ // http://my.opera.com/emoller/blog/2011/12/20/ // requestanimationframe-for-smart-er-animating // requestAnimationFrame polyfill by Erik Möller // fixes from Paul Irish and Tino Zijdel (function() { var lastTime = 0; var vendors = ['ms', 'moz', 'webkit', 'o']; for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame']; } if (!window.requestAnimationFrame) { window.requestAnimationFrame = function(callback, element) { var currTime = new Date().getTime(); var timeToCall = Math.max(0, 16 - (currTime - lastTime)); var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; } if (!window.cancelAnimationFrame) { window.cancelAnimationFrame = function(id) { clearTimeout(id); }; } }()); */ /** * shim for Uint8ClampedArray.slice * (allows arrayCopy to work with pixels[]) * with thanks to http://halfpapstudios.com/blog/tag/html5-canvas/ * Enumerable set to false to protect for...in from * Uint8ClampedArray.prototype pollution. */ (function () { 'use strict'; if (typeof Uint8ClampedArray !== 'undefined' && !Uint8ClampedArray.prototype.slice) { Object.defineProperty(Uint8ClampedArray.prototype, 'slice', { value: Array.prototype.slice, writable: true, configurable: true, enumerable: false }); } }()); },{}],16:[function(_dereq_,module,exports){ /** * @module Structure * @submodule Structure * @for p5 * @requires core */ 'use strict'; var p5 = _dereq_('./core'); p5.prototype.exit = function() { throw 'exit() not implemented, see remove()'; }; /** * Stops p5.js from continuously executing the code within draw(). * If loop() is called, the code in draw() begins to run continuously again. * If using noLoop() in setup(), it should be the last line inside the block. *

* When noLoop() is used, it's not possible to manipulate or access the * screen inside event handling functions such as mousePressed() or * keyPressed(). Instead, use those functions to call redraw() or loop(), * which will run draw(), which can update the screen properly. This means * that when noLoop() has been called, no drawing can happen, and functions * like saveFrame() or loadPixels() may not be used. *

* Note that if the sketch is resized, redraw() will be called to update * the sketch, even after noLoop() has been specified. Otherwise, the sketch * would enter an odd state until loop() was called. * * @method noLoop * @example *
* function setup() { * createCanvas(100, 100); * background(200); * noLoop(); * } * function draw() { * line(10, 10, 90, 90); * } *
* *
* var x = 0; * function setup() { * createCanvas(100, 100); * } * * function draw() { * background(204); * x = x + 0.1; * if (x > width) { * x = 0; * } * line(x, 0, x, height); * } * * function mousePressed() { * noLoop(); * } * * function mouseReleased() { * loop(); * } *
* * @alt * 113 pixel long line extending from top-left to bottom right of canvas. * horizontal line moves slowly from left. Loops but stops on mouse press. * */ p5.prototype.noLoop = function() { this._loop = false; }; /** * By default, p5.js loops through draw() continuously, executing the code * within it. However, the draw() loop may be stopped by calling noLoop(). * In that case, the draw() loop can be resumed with loop(). * * @method loop * @example *
* var x = 0; * function setup() { * createCanvas(100, 100); * noLoop(); * } * * function draw() { * background(204); * x = x + 0.1; * if (x > width) { * x = 0; * } * line(x, 0, x, height); * } * * function mousePressed() { * loop(); * } * * function mouseReleased() { * noLoop(); * } *
* * @alt * horizontal line moves slowly from left. Loops but stops on mouse press. * */ p5.prototype.loop = function() { this._loop = true; this._draw(); }; /** * The push() function saves the current drawing style settings and * transformations, while pop() restores these settings. Note that these * functions are always used together. They allow you to change the style * and transformation settings and later return to what you had. When a new * state is started with push(), it builds on the current style and transform * information. The push() and pop() functions can be embedded to provide * more control. (See the second example for a demonstration.) *

* push() stores information related to the current transformation state * and style settings controlled by the following functions: fill(), * stroke(), tint(), strokeWeight(), strokeCap(), strokeJoin(), * imageMode(), rectMode(), ellipseMode(), colorMode(), textAlign(), * textFont(), textMode(), textSize(), textLeading(). * * @method push * @example *
* * ellipse(0, 50, 33, 33); // Left circle * * push(); // Start a new drawing state * strokeWeight(10); * fill(204, 153, 0); * translate(50, 0); * ellipse(0, 50, 33, 33); // Middle circle * pop(); // Restore original state * * ellipse(100, 50, 33, 33); // Right circle * *
*
* * ellipse(0, 50, 33, 33); // Left circle * * push(); // Start a new drawing state * strokeWeight(10); * fill(204, 153, 0); * ellipse(33, 50, 33, 33); // Left-middle circle * * push(); // Start another new drawing state * stroke(0, 102, 153); * ellipse(66, 50, 33, 33); // Right-middle circle * pop(); // Restore previous state * * pop(); // Restore original state * * ellipse(100, 50, 33, 33); // Right circle * *
* * @alt * Gold ellipse + thick black outline @center 2 white ellipses on left and right. * 2 Gold ellipses left black right blue stroke. 2 white ellipses on left+right. * */ p5.prototype.push = function () { this._renderer.push(); this._styles.push({ _doStroke: this._renderer._doStroke, _strokeSet: this._renderer._strokeSet, _doFill: this._renderer._doFill, _fillSet: this._renderer._fillSet, _tint: this._renderer._tint, _imageMode: this._renderer._imageMode, _rectMode: this._renderer._rectMode, _ellipseMode: this._renderer._ellipseMode, _colorMode: this._renderer._colorMode, _textFont: this._renderer._textFont, _textLeading: this._renderer._textLeading, _textSize: this._renderer._textSize, _textStyle: this._renderer._textStyle }); }; /** * The push() function saves the current drawing style settings and * transformations, while pop() restores these settings. Note that these * functions are always used together. They allow you to change the style * and transformation settings and later return to what you had. When a new * state is started with push(), it builds on the current style and transform * information. The push() and pop() functions can be embedded to provide * more control. (See the second example for a demonstration.) *

* push() stores information related to the current transformation state * and style settings controlled by the following functions: fill(), * stroke(), tint(), strokeWeight(), strokeCap(), strokeJoin(), * imageMode(), rectMode(), ellipseMode(), colorMode(), textAlign(), * textFont(), textMode(), textSize(), textLeading(). * * @method pop * @example *
* * ellipse(0, 50, 33, 33); // Left circle * * push(); // Start a new drawing state * translate(50, 0); * strokeWeight(10); * fill(204, 153, 0); * ellipse(0, 50, 33, 33); // Middle circle * pop(); // Restore original state * * ellipse(100, 50, 33, 33); // Right circle * *
*
* * ellipse(0, 50, 33, 33); // Left circle * * push(); // Start a new drawing state * strokeWeight(10); * fill(204, 153, 0); * ellipse(33, 50, 33, 33); // Left-middle circle * * push(); // Start another new drawing state * stroke(0, 102, 153); * ellipse(66, 50, 33, 33); // Right-middle circle * pop(); // Restore previous state * * pop(); // Restore original state * * ellipse(100, 50, 33, 33); // Right circle * *
* * @alt * Gold ellipse + thick black outline @center 2 white ellipses on left and right. * 2 Gold ellipses left black right blue stroke. 2 white ellipses on left+right. * */ p5.prototype.pop = function () { this._renderer.pop(); var lastS = this._styles.pop(); for(var prop in lastS){ this._renderer[prop] = lastS[prop]; } }; p5.prototype.pushStyle = function() { throw new Error('pushStyle() not used, see push()'); }; p5.prototype.popStyle = function() { throw new Error('popStyle() not used, see pop()'); }; /** * * Executes the code within draw() one time. This functions allows the * program to update the display window only when necessary, for example * when an event registered by mousePressed() or keyPressed() occurs. *

* In structuring a program, it only makes sense to call redraw() within * events such as mousePressed(). This is because redraw() does not run * draw() immediately (it only sets a flag that indicates an update is * needed). *

* The redraw() function does not work properly when called inside draw(). * To enable/disable animations, use loop() and noLoop(). *

* In addition you can set the number of redraws per method call. Just * add an integer as single parameter for the number of redraws. * * @method redraw * @param {Integer} [n] Redraw for n-times. The default value is 1. * @example *
* var x = 0; * * function setup() { * createCanvas(100, 100); * noLoop(); * } * * function draw() { * background(204); * line(x, 0, x, height); * } * * function mousePressed() { * x += 1; * redraw(); * } *
* *
* var x = 0; * * function setup() { * createCanvas(100, 100); * noLoop(); * } * * function draw() { * background(204); * x += 1; * line(x, 0, x, height); * } * * function mousePressed() { * redraw(5); * } *
* * @alt * black line on far left of canvas * black line on far left of canvas * */ p5.prototype.redraw = function () { this.resetMatrix(); if(this._renderer.isP3D){ this._renderer._update(); } var numberOfRedraws = 1; if (arguments.length === 1) { try { if (parseInt(arguments[0]) > 1) { numberOfRedraws = parseInt(arguments[0]); } } catch (error) { // Do nothing, because the default value didn't be changed. } } var userSetup = this.setup || window.setup; var userDraw = this.draw || window.draw; if (typeof userDraw === 'function') { if (typeof userSetup === 'undefined') { this.scale(this._pixelDensity, this._pixelDensity); } var self = this; var callMethod = function (f) { f.call(self); }; for (var idxRedraw = 0; idxRedraw < numberOfRedraws; idxRedraw++) { this._registeredMethods.pre.forEach(callMethod); userDraw(); this._registeredMethods.post.forEach(callMethod); } } }; p5.prototype.size = function() { var s = 'size() is not a valid p5 function, to set the size of the '; s += 'drawing canvas, please use createCanvas() instead'; throw s; }; module.exports = p5; },{"./core":5}],17:[function(_dereq_,module,exports){ /** * @module Transform * @submodule Transform * @for p5 * @requires core * @requires constants */ 'use strict'; var p5 = _dereq_('./core'); var constants = _dereq_('./constants'); /** * Multiplies the current matrix by the one specified through the parameters. * This is very slow because it will try to calculate the inverse of the * transform, so avoid it whenever possible. * * @method applyMatrix * @param {Number} n00 numbers which define the 3x2 matrix to be multiplied * @param {Number} n01 numbers which define the 3x2 matrix to be multiplied * @param {Number} n02 numbers which define the 3x2 matrix to be multiplied * @param {Number} n10 numbers which define the 3x2 matrix to be multiplied * @param {Number} n11 numbers which define the 3x2 matrix to be multiplied * @param {Number} n12 numbers which define the 3x2 matrix to be multiplied * @chainable * @example *
* * // Example in the works. * *
* * @alt * no image diplayed * */ p5.prototype.applyMatrix = function(n00, n01, n02, n10, n11, n12) { this._renderer.applyMatrix(n00, n01, n02, n10, n11, n12); return this; }; p5.prototype.popMatrix = function() { throw new Error('popMatrix() not used, see pop()'); }; p5.prototype.printMatrix = function() { throw new Error('printMatrix() not implemented'); }; p5.prototype.pushMatrix = function() { throw new Error('pushMatrix() not used, see push()'); }; /** * Replaces the current matrix with the identity matrix. * * @method resetMatrix * @chainable * @example *
* * // Example in the works. * *
* * @alt * no image diplayed * */ p5.prototype.resetMatrix = function() { this._renderer.resetMatrix(); return this; }; /** * Rotates a shape the amount specified by the angle parameter. This * function accounts for angleMode, so angles can be entered in either * RADIANS or DEGREES. *

* Objects are always rotated around their relative position to the * origin and positive numbers rotate objects in a clockwise direction. * Transformations apply to everything that happens after and subsequent * calls to the function accumulates the effect. For example, calling * rotate(HALF_PI) and then rotate(HALF_PI) is the same as rotate(PI). * All tranformations are reset when draw() begins again. *

* Technically, rotate() multiplies the current transformation matrix * by a rotation matrix. This function can be further controlled by * the push() and pop(). * * @method rotate * @param {Number} angle the angle of rotation, specified in radians * or degrees, depending on current angleMode * @param {p5.Vector|Array} [axis] (in 3d) the axis to rotate around * @chainable * @example *
* * translate(width/2, height/2); * rotate(PI/3.0); * rect(-26, -26, 52, 52); * *
* * @alt * white 52x52 rect with black outline at center rotated counter 45 degrees * */ p5.prototype.rotate = function(angle, axis) { var args = new Array(arguments.length); var r; for (var i = 0; i < args.length; ++i) { args[i] = arguments[i]; } if (this._angleMode === constants.DEGREES) { r = this.radians(args[0]); } else if (this._angleMode === constants.RADIANS){ r = args[0]; } //in webgl mode if(args.length > 1){ this._renderer.rotate(r, args[1]); } else { this._renderer.rotate(r); } return this; }; /** * Rotates around X axis. * @method rotateX * @param {Number} rad angles in radians * @chainable */ p5.prototype.rotateX = function(rad) { if (this._renderer.isP3D) { this._renderer.rotateX(rad); } else { throw 'not supported in p2d. Please use webgl mode'; } return this; }; /** * Rotates around Y axis. * @method rotateY * @param {Number} rad angles in radians * @chainable */ p5.prototype.rotateY = function(rad) { if (this._renderer.isP3D) { this._renderer.rotateY(rad); } else { throw 'not supported in p2d. Please use webgl mode'; } return this; }; /** * Rotates around Z axis. Webgl mode only. * @method rotateZ * @param {Number} rad angles in radians * @chainable */ p5.prototype.rotateZ = function(rad) { if (this._renderer.isP3D) { this._renderer.rotateZ(rad); } else { throw 'not supported in p2d. Please use webgl mode'; } return this; }; /** * Increases or decreases the size of a shape by expanding and contracting * vertices. Objects always scale from their relative origin to the * coordinate system. Scale values are specified as decimal percentages. * For example, the function call scale(2.0) increases the dimension of a * shape by 200%. *

* Transformations apply to everything that happens after and subsequent * calls to the function multiply the effect. For example, calling scale(2.0) * and then scale(1.5) is the same as scale(3.0). If scale() is called * within draw(), the transformation is reset when the loop begins again. *

* Using this function with the z parameter is only available in WEBGL mode. * This function can be further controlled with push() and pop(). * * @method scale * @param {Number|p5.Vector|Array} s * percent to scale the object, or percentage to * scale the object in the x-axis if multiple arguments * are given * @param {Number} [y] percent to scale the object in the y-axis * @param {Number} [z] percent to scale the object in the z-axis (webgl only) * @chainable * @example *
* * translate(width/2, height/2); * rotate(PI/3.0); * rect(-26, -26, 52, 52); * *
* *
* * rect(30, 20, 50, 50); * scale(0.5, 1.3); * rect(30, 20, 50, 50); * *
* * @alt * white 52x52 rect with black outline at center rotated counter 45 degrees * 2 white rects with black outline- 1 50x50 at center. other 25x65 bottom left * */ p5.prototype.scale = function() { var x,y,z; var args = new Array(arguments.length); for(var i = 0; i < args.length; i++) { args[i] = arguments[i]; } // Only check for Vector argument type if Vector is available if (typeof p5.Vector !== 'undefined') { if(args[0] instanceof p5.Vector){ x = args[0].x; y = args[0].y; z = args[0].z; } } else if(args[0] instanceof Array){ x = args[0][0]; y = args[0][1]; z = args[0][2] || 1; } else { if(args.length === 1){ x = y = z = args[0]; } else { x = args[0]; y = args[1]; z = args[2] || 1; } } if(this._renderer.isP3D){ this._renderer.scale.call(this._renderer, x,y,z); } else { this._renderer.scale.call(this._renderer, x,y); } return this; }; /** * Shears a shape around the x-axis the amount specified by the angle * parameter. Angles should be specified in the current angleMode. * Objects are always sheared around their relative position to the origin * and positive numbers shear objects in a clockwise direction. *

* Transformations apply to everything that happens after and subsequent * calls to the function accumulates the effect. For example, calling * shearX(PI/2) and then shearX(PI/2) is the same as shearX(PI). * If shearX() is called within the draw(), the transformation is reset when * the loop begins again. *

* Technically, shearX() multiplies the current transformation matrix by a * rotation matrix. This function can be further controlled by the * push() and pop() functions. * * @method shearX * @param {Number} angle angle of shear specified in radians or degrees, * depending on current angleMode * @chainable * @example *
* * translate(width/4, height/4); * shearX(PI/4.0); * rect(0, 0, 30, 30); * *
* * @alt * white irregular quadrilateral with black outline at top middle. * */ p5.prototype.shearX = function(angle) { if (this._angleMode === constants.DEGREES) { angle = this.radians(angle); } this._renderer.shearX(angle); return this; }; /** * Shears a shape around the y-axis the amount specified by the angle * parameter. Angles should be specified in the current angleMode. Objects * are always sheared around their relative position to the origin and * positive numbers shear objects in a clockwise direction. *

* Transformations apply to everything that happens after and subsequent * calls to the function accumulates the effect. For example, calling * shearY(PI/2) and then shearY(PI/2) is the same as shearY(PI). If * shearY() is called within the draw(), the transformation is reset when * the loop begins again. *

* Technically, shearY() multiplies the current transformation matrix by a * rotation matrix. This function can be further controlled by the * push() and pop() functions. * * @method shearY * @param {Number} angle angle of shear specified in radians or degrees, * depending on current angleMode * @chainable * @example *
* * translate(width/4, height/4); * shearY(PI/4.0); * rect(0, 0, 30, 30); * *
* * @alt * white irregular quadrilateral with black outline at middle bottom. * */ p5.prototype.shearY = function(angle) { if (this._angleMode === constants.DEGREES) { angle = this.radians(angle); } this._renderer.shearY(angle); return this; }; /** * Specifies an amount to displace objects within the display window. * The x parameter specifies left/right translation, the y parameter * specifies up/down translation. *

* Transformations are cumulative and apply to everything that happens after * and subsequent calls to the function accumulates the effect. For example, * calling translate(50, 0) and then translate(20, 0) is the same as * translate(70, 0). If translate() is called within draw(), the * transformation is reset when the loop begins again. This function can be * further controlled by using push() and pop(). * * @method translate * @param {Number} x left/right translation * @param {Number} y up/down translation * @param {Number} [z] forward/backward translation (webgl only) * @chainable * @example *
* * translate(30, 20); * rect(0, 0, 55, 55); * *
* *
* * rect(0, 0, 55, 55); // Draw rect at original 0,0 * translate(30, 20); * rect(0, 0, 55, 55); // Draw rect at new 0,0 * translate(14, 14); * rect(0, 0, 55, 55); // Draw rect at new 0,0 * *
* * @alt * white 55x55 rect with black outline at center right. * 3 white 55x55 rects with black outlines at top-l, center-r and bottom-r. * */ p5.prototype.translate = function(x, y, z) { if (this._renderer.isP3D) { this._renderer.translate(x, y, z); } else { this._renderer.translate(x, y); } return this; }; module.exports = p5; },{"./constants":4,"./core":5}],18:[function(_dereq_,module,exports){ /** * @module Shape * @submodule Vertex * @for p5 * @requires core * @requires constants */ 'use strict'; var p5 = _dereq_('./core'); var constants = _dereq_('./constants'); var shapeKind = null; var vertices = []; var contourVertices = []; var isBezier = false; var isCurve = false; var isQuadratic = false; var isContour = false; var isFirstContour = true; /** * Use the beginContour() and endContour() functions to create negative * shapes within shapes such as the center of the letter 'O'. beginContour() * begins recording vertices for the shape and endContour() stops recording. * The vertices that define a negative shape must "wind" in the opposite * direction from the exterior shape. First draw vertices for the exterior * clockwise order, then for internal shapes, draw vertices * shape in counter-clockwise. *

* These functions can only be used within a beginShape()/endShape() pair and * transformations such as translate(), rotate(), and scale() do not work * within a beginContour()/endContour() pair. It is also not possible to use * other shapes, such as ellipse() or rect() within. * * @method beginContour * @chainable * @example *
* * translate(50, 50); * stroke(255, 0, 0); * beginShape(); * // Exterior part of shape, clockwise winding * vertex(-40, -40); * vertex(40, -40); * vertex(40, 40); * vertex(-40, 40); * // Interior part of shape, counter-clockwise winding * beginContour(); * vertex(-20, -20); * vertex(-20, 20); * vertex(20, 20); * vertex(20, -20); * endContour(); * endShape(CLOSE); * *
* * @alt * white rect and smaller grey rect with red outlines in center of canvas. * */ p5.prototype.beginContour = function() { contourVertices = []; isContour = true; return this; }; /** * Using the beginShape() and endShape() functions allow creating more * complex forms. beginShape() begins recording vertices for a shape and * endShape() stops recording. The value of the kind parameter tells it which * types of shapes to create from the provided vertices. With no mode * specified, the shape can be any irregular polygon. *

* The parameters available for beginShape() are POINTS, LINES, TRIANGLES, * TRIANGLE_FAN, TRIANGLE_STRIP, QUADS, and QUAD_STRIP. After calling the * beginShape() function, a series of vertex() commands must follow. To stop * drawing the shape, call endShape(). Each shape will be outlined with the * current stroke color and filled with the fill color. *

* Transformations such as translate(), rotate(), and scale() do not work * within beginShape(). It is also not possible to use other shapes, such as * ellipse() or rect() within beginShape(). * * @method beginShape * @param {Constant} [kind] either POINTS, LINES, TRIANGLES, TRIANGLE_FAN * TRIANGLE_STRIP, QUADS, or QUAD_STRIP * @chainable * @example *
* * beginShape(); * vertex(30, 20); * vertex(85, 20); * vertex(85, 75); * vertex(30, 75); * endShape(CLOSE); * *
* *
* * // currently not working * beginShape(POINTS); * vertex(30, 20); * vertex(85, 20); * vertex(85, 75); * vertex(30, 75); * endShape(); * *
* *
* * beginShape(LINES); * vertex(30, 20); * vertex(85, 20); * vertex(85, 75); * vertex(30, 75); * endShape(); * *
* *
* * noFill(); * beginShape(); * vertex(30, 20); * vertex(85, 20); * vertex(85, 75); * vertex(30, 75); * endShape(); * *
* *
* * noFill(); * beginShape(); * vertex(30, 20); * vertex(85, 20); * vertex(85, 75); * vertex(30, 75); * endShape(CLOSE); * *
* *
* * beginShape(TRIANGLES); * vertex(30, 75); * vertex(40, 20); * vertex(50, 75); * vertex(60, 20); * vertex(70, 75); * vertex(80, 20); * endShape(); * *
* *
* * beginShape(TRIANGLE_STRIP); * vertex(30, 75); * vertex(40, 20); * vertex(50, 75); * vertex(60, 20); * vertex(70, 75); * vertex(80, 20); * vertex(90, 75); * endShape(); * *
* *
* * beginShape(TRIANGLE_FAN); * vertex(57.5, 50); * vertex(57.5, 15); * vertex(92, 50); * vertex(57.5, 85); * vertex(22, 50); * vertex(57.5, 15); * endShape(); * *
* *
* * beginShape(QUADS); * vertex(30, 20); * vertex(30, 75); * vertex(50, 75); * vertex(50, 20); * vertex(65, 20); * vertex(65, 75); * vertex(85, 75); * vertex(85, 20); * endShape(); * *
* *
* * beginShape(QUAD_STRIP); * vertex(30, 20); * vertex(30, 75); * vertex(50, 20); * vertex(50, 75); * vertex(65, 20); * vertex(65, 75); * vertex(85, 20); * vertex(85, 75); * endShape(); * *
* *
* * beginShape(); * vertex(20, 20); * vertex(40, 20); * vertex(40, 40); * vertex(60, 40); * vertex(60, 60); * vertex(20, 60); * endShape(CLOSE); * *
* @alt * white square-shape with black outline in middle-right of canvas. * 4 black points in a square shape in middle-right of canvas. * 2 horizontal black lines. In the top-right and bottom-right of canvas. * 3 line shape with horizontal on top, vertical in middle and horizontal bottom. * square line shape in middle-right of canvas. * 2 white triangle shapes mid-right canvas. left one pointing up and right down. * 5 horizontal interlocking and alternating white triangles in mid-right canvas. * 4 interlocking white triangles in 45 degree rotated square-shape. * 2 white rectangle shapes in mid-right canvas. Both 20x55. * 3 side-by-side white rectangles center rect is smaller in mid-right canvas. * Thick white l-shape with black outline mid-top-left of canvas. * */ p5.prototype.beginShape = function(kind) { if (kind === constants.POINTS || kind === constants.LINES || kind === constants.TRIANGLES || kind === constants.TRIANGLE_FAN || kind === constants.TRIANGLE_STRIP || kind === constants.QUADS || kind === constants.QUAD_STRIP) { shapeKind = kind; } else { shapeKind = null; } if(this._renderer.isP3D){ this._renderer.beginShape(kind); } else { vertices = []; contourVertices = []; } return this; }; /** * Specifies vertex coordinates for Bezier curves. Each call to * bezierVertex() defines the position of two control points and * one anchor point of a Bezier curve, adding a new segment to a * line or shape. *

* The first time bezierVertex() is used within a * beginShape() call, it must be prefaced with a call to vertex() * to set the first anchor point. This function must be used between * beginShape() and endShape() and only when there is no MODE * parameter specified to beginShape(). * * @method bezierVertex * @param {Number} x2 x-coordinate for the first control point * @param {Number} y2 y-coordinate for the first control point * @param {Number} x3 x-coordinate for the second control point * @param {Number} y3 y-coordinate for the second control point * @param {Number} x4 x-coordinate for the anchor point * @param {Number} y4 y-coordinate for the anchor point * @chainable * @example *
* * noFill(); * beginShape(); * vertex(30, 20); * bezierVertex(80, 0, 80, 75, 30, 75); * endShape(); * *
* *
* * beginShape(); * vertex(30, 20); * bezierVertex(80, 0, 80, 75, 30, 75); * bezierVertex(50, 80, 60, 25, 30, 20); * endShape(); * *
* * @alt * crescent-shaped line in middle of canvas. Points facing left. * white crescent shape in middle of canvas. Points facing left. * */ p5.prototype.bezierVertex = function(x2, y2, x3, y3, x4, y4) { if (vertices.length === 0) { throw 'vertex() must be used once before calling bezierVertex()'; } else { isBezier = true; var vert = []; for (var i = 0; i < arguments.length; i++) { vert[i] = arguments[i]; } vert.isVert = false; if (isContour) { contourVertices.push(vert); } else { vertices.push(vert); } } return this; }; /** * Specifies vertex coordinates for curves. This function may only * be used between beginShape() and endShape() and only when there * is no MODE parameter specified to beginShape(). *

* The first and last points in a series of curveVertex() lines will be used to * guide the beginning and end of a the curve. A minimum of four * points is required to draw a tiny curve between the second and * third points. Adding a fifth point with curveVertex() will draw * the curve between the second, third, and fourth points. The * curveVertex() function is an implementation of Catmull-Rom * splines. * * @method curveVertex * @param {Number} x x-coordinate of the vertex * @param {Number} y y-coordinate of the vertex * @chainable * @example *
* * noFill(); * beginShape(); * curveVertex(84, 91); * curveVertex(84, 91); * curveVertex(68, 19); * curveVertex(21, 17); * curveVertex(32, 100); * curveVertex(32, 100); * endShape(); * *
* * @alt * Upside-down u-shape line, mid canvas. left point extends beyond canvas view. * */ p5.prototype.curveVertex = function(x,y) { isCurve = true; this.vertex(x, y); return this; }; /** * Use the beginContour() and endContour() functions to create negative * shapes within shapes such as the center of the letter 'O'. beginContour() * begins recording vertices for the shape and endContour() stops recording. * The vertices that define a negative shape must "wind" in the opposite * direction from the exterior shape. First draw vertices for the exterior * clockwise order, then for internal shapes, draw vertices * shape in counter-clockwise. *

* These functions can only be used within a beginShape()/endShape() pair and * transformations such as translate(), rotate(), and scale() do not work * within a beginContour()/endContour() pair. It is also not possible to use * other shapes, such as ellipse() or rect() within. * * @method endContour * @chainable * @example *
* * translate(50, 50); * stroke(255, 0, 0); * beginShape(); * // Exterior part of shape, clockwise winding * vertex(-40, -40); * vertex(40, -40); * vertex(40, 40); * vertex(-40, 40); * // Interior part of shape, counter-clockwise winding * beginContour(); * vertex(-20, -20); * vertex(-20, 20); * vertex(20, 20); * vertex(20, -20); * endContour(); * endShape(CLOSE); * *
* * @alt * white rect and smaller grey rect with red outlines in center of canvas. * */ p5.prototype.endContour = function() { var vert = contourVertices[0].slice(); // copy all data vert.isVert = contourVertices[0].isVert; vert.moveTo = false; contourVertices.push(vert); // prevent stray lines with multiple contours if (isFirstContour) { vertices.push(vertices[0]); isFirstContour = false; } for (var i = 0; i < contourVertices.length; i++) { vertices.push(contourVertices[i]); } return this; }; /** * The endShape() function is the companion to beginShape() and may only be * called after beginShape(). When endshape() is called, all of image data * defined since the previous call to beginShape() is written into the image * buffer. The constant CLOSE as the value for the MODE parameter to close * the shape (to connect the beginning and the end). * * @method endShape * @param {Constant} [mode] use CLOSE to close the shape * @chainable * @example *
* * noFill(); * * beginShape(); * vertex(20, 20); * vertex(45, 20); * vertex(45, 80); * endShape(CLOSE); * * beginShape(); * vertex(50, 20); * vertex(75, 20); * vertex(75, 80); * endShape(); * *
* * @alt * Triangle line shape with smallest interior angle on bottom and upside-down L. * */ p5.prototype.endShape = function(mode) { if(this._renderer.isP3D){ this._renderer.endShape(mode, isCurve, isBezier, isQuadratic, isContour, shapeKind); }else{ if (vertices.length === 0) { return this; } if (!this._renderer._doStroke && !this._renderer._doFill) { return this; } var closeShape = mode === constants.CLOSE; // if the shape is closed, the first element is also the last element if (closeShape && !isContour) { vertices.push(vertices[0]); } this._renderer.endShape(mode, vertices, isCurve, isBezier, isQuadratic, isContour, shapeKind); // Reset some settings isCurve = false; isBezier = false; isQuadratic = false; isContour = false; isFirstContour = true; // If the shape is closed, the first element was added as last element. // We must remove it again to prevent the list of vertices from growing // over successive calls to endShape(CLOSE) if (closeShape) { vertices.pop(); } } return this; }; /** * Specifies vertex coordinates for quadratic Bezier curves. Each call to * quadraticVertex() defines the position of one control points and one * anchor point of a Bezier curve, adding a new segment to a line or shape. * The first time quadraticVertex() is used within a beginShape() call, it * must be prefaced with a call to vertex() to set the first anchor point. * This function must be used between beginShape() and endShape() and only * when there is no MODE parameter specified to beginShape(). * * @method quadraticVertex * @param {Number} cx x-coordinate for the control point * @param {Number} cy y-coordinate for the control point * @param {Number} x3 x-coordinate for the anchor point * @param {Number} y3 y-coordinate for the anchor point * @chainable * @example *
* * noFill(); * strokeWeight(4); * beginShape(); * vertex(20, 20); * quadraticVertex(80, 20, 50, 50); * endShape(); * *
* *
* * noFill(); * strokeWeight(4); * beginShape(); * vertex(20, 20); * quadraticVertex(80, 20, 50, 50); * quadraticVertex(20, 80, 80, 80); * vertex(80, 60); * endShape(); * *
* * @alt * arched-shaped black line with 4 pixel thick stroke weight. * backwards s-shaped black line with 4 pixel thick stroke weight. * */ p5.prototype.quadraticVertex = function(cx, cy, x3, y3) { //if we're drawing a contour, put the points into an // array for inside drawing if(this._contourInited) { var pt = {}; pt.x = cx; pt.y = cy; pt.x3 = x3; pt.y3 = y3; pt.type = constants.QUADRATIC; this._contourVertices.push(pt); return this; } if (vertices.length > 0) { isQuadratic = true; var vert = []; for (var i = 0; i < arguments.length; i++) { vert[i] = arguments[i]; } vert.isVert = false; if (isContour) { contourVertices.push(vert); } else { vertices.push(vert); } } else { throw 'vertex() must be used once before calling quadraticVertex()'; } return this; }; /** * All shapes are constructed by connecting a series of vertices. vertex() * is used to specify the vertex coordinates for points, lines, triangles, * quads, and polygons. It is used exclusively within the beginShape() and * endShape() functions. * * @method vertex * @param {Number} x x-coordinate of the vertex * @param {Number} y y-coordinate of the vertex * @param {Number|Boolean} [z] z-coordinate of the vertex * @chainable * @example *
* * beginShape(POINTS); * vertex(30, 20); * vertex(85, 20); * vertex(85, 75); * vertex(30, 75); * endShape(); * *
* * @alt * 4 black points in a square shape in middle-right of canvas. * */ p5.prototype.vertex = function(x, y, moveTo) { if(this._renderer.isP3D){ this._renderer.vertex(x, y, moveTo); }else{ var vert = []; vert.isVert = true; vert[0] = x; vert[1] = y; vert[2] = 0; vert[3] = 0; vert[4] = 0; vert[5] = this._renderer._getFill(); vert[6] = this._renderer._getStroke(); if (moveTo) { vert.moveTo = moveTo; } if (isContour) { if (contourVertices.length === 0) { vert.moveTo = true; } contourVertices.push(vert); } else { vertices.push(vert); } } return this; }; module.exports = p5; },{"./constants":4,"./core":5}],19:[function(_dereq_,module,exports){ /*global ImageData:false */ /** * This module defines the filters for use with image buffers. * * This module is basically a collection of functions stored in an object * as opposed to modules. The functions are destructive, modifying * the passed in canvas rather than creating a copy. * * Generally speaking users of this module will use the Filters.apply method * on a canvas to create an effect. * * A number of functions are borrowed/adapted from * http://www.html5rocks.com/en/tutorials/canvas/imagefilters/ * or the java processing implementation. */ 'use strict'; var Filters = {}; /* * Helper functions */ /** * Returns the pixel buffer for a canvas * * @private * * @param {Canvas|ImageData} canvas the canvas to get pixels from * @return {Uint8ClampedArray} a one-dimensional array containing * the data in thc RGBA order, with integer * values between 0 and 255 */ Filters._toPixels = function (canvas) { if (canvas instanceof ImageData) { return canvas.data; } else { return canvas.getContext('2d').getImageData( 0, 0, canvas.width, canvas.height ).data; } }; /** * Returns a 32 bit number containing ARGB data at ith pixel in the * 1D array containing pixels data. * * @private * * @param {Uint8ClampedArray} data array returned by _toPixels() * @param {Integer} i index of a 1D Image Array * @return {Integer} 32 bit integer value representing * ARGB value. */ Filters._getARGB = function (data, i) { var offset = i * 4; return (data[offset+3] << 24) & 0xff000000 | (data[offset] << 16) & 0x00ff0000 | (data[offset+1] << 8) & 0x0000ff00 | data[offset+2] & 0x000000ff; }; /** * Modifies pixels RGBA values to values contained in the data object. * * @private * * @param {Uint8ClampedArray} pixels array returned by _toPixels() * @param {Int32Array} data source 1D array where each value * represents ARGB values */ Filters._setPixels = function (pixels, data) { var offset = 0; for( var i = 0, al = pixels.length; i < al; i++) { offset = i*4; pixels[offset + 0] = (data[i] & 0x00ff0000)>>>16; pixels[offset + 1] = (data[i] & 0x0000ff00)>>>8; pixels[offset + 2] = (data[i] & 0x000000ff); pixels[offset + 3] = (data[i] & 0xff000000)>>>24; } }; /** * Returns the ImageData object for a canvas * https://developer.mozilla.org/en-US/docs/Web/API/ImageData * * @private * * @param {Canvas|ImageData} canvas canvas to get image data from * @return {ImageData} Holder of pixel data (and width and * height) for a canvas */ Filters._toImageData = function (canvas) { if (canvas instanceof ImageData) { return canvas; } else { return canvas.getContext('2d').getImageData( 0, 0, canvas.width, canvas.height ); } }; /** * Returns a blank ImageData object. * * @private * * @param {Integer} width * @param {Integer} height * @return {ImageData} */ Filters._createImageData = function (width, height) { Filters._tmpCanvas = document.createElement('canvas'); Filters._tmpCtx = Filters._tmpCanvas.getContext('2d'); return this._tmpCtx.createImageData(width, height); }; /** * Applys a filter function to a canvas. * * The difference between this and the actual filter functions defined below * is that the filter functions generally modify the pixel buffer but do * not actually put that data back to the canvas (where it would actually * update what is visible). By contrast this method does make the changes * actually visible in the canvas. * * The apply method is the method that callers of this module would generally * use. It has been separated from the actual filters to support an advanced * use case of creating a filter chain that executes without actually updating * the canvas in between everystep. * * @param {HTMLCanvasElement} canvas [description] * @param {function(ImageData,Object)} func [description] * @param {Object} filterParam [description] */ Filters.apply = function (canvas, func, filterParam) { var ctx = canvas.getContext('2d'); var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); //Filters can either return a new ImageData object, or just modify //the one they received. var newImageData = func(imageData, filterParam); if (newImageData instanceof ImageData) { ctx.putImageData(newImageData, 0, 0, 0, 0, canvas.width, canvas.height); } else { ctx.putImageData(imageData, 0, 0, 0, 0, canvas.width, canvas.height); } }; /* * Filters */ /** * Converts the image to black and white pixels depending if they are above or * below the threshold defined by the level parameter. The parameter must be * between 0.0 (black) and 1.0 (white). If no level is specified, 0.5 is used. * * Borrowed from http://www.html5rocks.com/en/tutorials/canvas/imagefilters/ * * @param {Canvas} canvas * @param {Float} level */ Filters.threshold = function (canvas, level) { var pixels = Filters._toPixels(canvas); if (level === undefined) { level = 0.5; } var thresh = Math.floor(level * 255); for (var i = 0; i < pixels.length; i += 4) { var r = pixels[i]; var g = pixels[i + 1]; var b = pixels[i + 2]; var gray = (0.2126 * r + 0.7152 * g + 0.0722 * b); var val; if (gray >= thresh) { val = 255; } else { val = 0; } pixels[i] = pixels[i + 1] = pixels[i + 2] = val; } }; /** * Converts any colors in the image to grayscale equivalents. * No parameter is used. * * Borrowed from http://www.html5rocks.com/en/tutorials/canvas/imagefilters/ * * @param {Canvas} canvas */ Filters.gray = function (canvas) { var pixels = Filters._toPixels(canvas); for (var i = 0; i < pixels.length; i += 4) { var r = pixels[i]; var g = pixels[i + 1]; var b = pixels[i + 2]; // CIE luminance for RGB var gray = (0.2126 * r + 0.7152 * g + 0.0722 * b); pixels[i] = pixels[i + 1] = pixels[i + 2] = gray; } }; /** * Sets the alpha channel to entirely opaque. No parameter is used. * * @param {Canvas} canvas */ Filters.opaque = function (canvas) { var pixels = Filters._toPixels(canvas); for (var i = 0; i < pixels.length; i += 4) { pixels[i + 3] = 255; } return pixels; }; /** * Sets each pixel to its inverse value. No parameter is used. * @param {Canvas} canvas */ Filters.invert = function (canvas) { var pixels = Filters._toPixels(canvas); for (var i = 0; i < pixels.length; i += 4) { pixels[i] = 255 - pixels[i]; pixels[i + 1] = 255 - pixels[i + 1]; pixels[i + 2] = 255 - pixels[i + 2]; } }; /** * Limits each channel of the image to the number of colors specified as * the parameter. The parameter can be set to values between 2 and 255, but * results are most noticeable in the lower ranges. * * Adapted from java based processing implementation * * @param {Canvas} canvas * @param {Integer} level */ Filters.posterize = function (canvas, level) { var pixels = Filters._toPixels(canvas); if ((level < 2) || (level > 255)) { throw new Error( 'Level must be greater than 2 and less than 255 for posterize' ); } var levels1 = level - 1; for (var i = 0; i < pixels.length; i+=4) { var rlevel = pixels[i]; var glevel = pixels[i + 1]; var blevel = pixels[i + 2]; pixels[i] = (((rlevel * level) >> 8) * 255) / levels1; pixels[i + 1] = (((glevel * level) >> 8) * 255) / levels1; pixels[i + 2] = (((blevel * level) >> 8) * 255) / levels1; } }; /** * reduces the bright areas in an image * @param {Canvas} canvas * */ Filters.dilate = function (canvas) { var pixels = Filters._toPixels(canvas); var currIdx = 0; var maxIdx = pixels.length ? pixels.length/4 : 0; var out = new Int32Array(maxIdx); var currRowIdx, maxRowIdx, colOrig, colOut, currLum; var idxRight, idxLeft, idxUp, idxDown, colRight, colLeft, colUp, colDown, lumRight, lumLeft, lumUp, lumDown; while(currIdx < maxIdx) { currRowIdx = currIdx; maxRowIdx = currIdx + canvas.width; while (currIdx < maxRowIdx) { colOrig = colOut = Filters._getARGB(pixels, currIdx); idxLeft = currIdx - 1; idxRight = currIdx + 1; idxUp = currIdx - canvas.width; idxDown = currIdx + canvas.width; if (idxLeft < currRowIdx) { idxLeft = currIdx; } if (idxRight >= maxRowIdx) { idxRight = currIdx; } if (idxUp < 0){ idxUp = 0; } if (idxDown >= maxIdx) { idxDown = currIdx; } colUp = Filters._getARGB(pixels, idxUp); colLeft = Filters._getARGB(pixels, idxLeft); colDown = Filters._getARGB(pixels, idxDown); colRight = Filters._getARGB(pixels, idxRight); //compute luminance currLum = 77*(colOrig>>16&0xff) + 151*(colOrig>>8&0xff) + 28*(colOrig&0xff); lumLeft = 77*(colLeft>>16&0xff) + 151*(colLeft>>8&0xff) + 28*(colLeft&0xff); lumRight = 77*(colRight>>16&0xff) + 151*(colRight>>8&0xff) + 28*(colRight&0xff); lumUp = 77*(colUp>>16&0xff) + 151*(colUp>>8&0xff) + 28*(colUp&0xff); lumDown = 77*(colDown>>16&0xff) + 151*(colDown>>8&0xff) + 28*(colDown&0xff); if (lumLeft > currLum) { colOut = colLeft; currLum = lumLeft; } if (lumRight > currLum) { colOut = colRight; currLum = lumRight; } if (lumUp > currLum) { colOut = colUp; currLum = lumUp; } if (lumDown > currLum) { colOut = colDown; currLum = lumDown; } out[currIdx++]=colOut; } } Filters._setPixels(pixels, out); }; /** * increases the bright areas in an image * @param {Canvas} canvas * */ Filters.erode = function(canvas) { var pixels = Filters._toPixels(canvas); var currIdx = 0; var maxIdx = pixels.length ? pixels.length/4 : 0; var out = new Int32Array(maxIdx); var currRowIdx, maxRowIdx, colOrig, colOut, currLum; var idxRight, idxLeft, idxUp, idxDown, colRight, colLeft, colUp, colDown, lumRight, lumLeft, lumUp, lumDown; while(currIdx < maxIdx) { currRowIdx = currIdx; maxRowIdx = currIdx + canvas.width; while (currIdx < maxRowIdx) { colOrig = colOut = Filters._getARGB(pixels, currIdx); idxLeft = currIdx - 1; idxRight = currIdx + 1; idxUp = currIdx - canvas.width; idxDown = currIdx + canvas.width; if (idxLeft < currRowIdx) { idxLeft = currIdx; } if (idxRight >= maxRowIdx) { idxRight = currIdx; } if (idxUp < 0) { idxUp = 0; } if (idxDown >= maxIdx) { idxDown = currIdx; } colUp = Filters._getARGB(pixels, idxUp); colLeft = Filters._getARGB(pixels, idxLeft); colDown = Filters._getARGB(pixels, idxDown); colRight = Filters._getARGB(pixels, idxRight); //compute luminance currLum = 77*(colOrig>>16&0xff) + 151*(colOrig>>8&0xff) + 28*(colOrig&0xff); lumLeft = 77*(colLeft>>16&0xff) + 151*(colLeft>>8&0xff) + 28*(colLeft&0xff); lumRight = 77*(colRight>>16&0xff) + 151*(colRight>>8&0xff) + 28*(colRight&0xff); lumUp = 77*(colUp>>16&0xff) + 151*(colUp>>8&0xff) + 28*(colUp&0xff); lumDown = 77*(colDown>>16&0xff) + 151*(colDown>>8&0xff) + 28*(colDown&0xff); if (lumLeft < currLum) { colOut = colLeft; currLum = lumLeft; } if (lumRight < currLum) { colOut = colRight; currLum = lumRight; } if (lumUp < currLum) { colOut = colUp; currLum = lumUp; } if (lumDown < currLum) { colOut = colDown; currLum = lumDown; } out[currIdx++]=colOut; } } Filters._setPixels(pixels, out); }; // BLUR // internal kernel stuff for the gaussian blur filter var blurRadius; var blurKernelSize; var blurKernel; var blurMult; /* * Port of https://github.com/processing/processing/blob/ * master/core/src/processing/core/PImage.java#L1250 * * Optimized code for building the blur kernel. * further optimized blur code (approx. 15% for radius=20) * bigger speed gains for larger radii (~30%) * added support for various image types (ALPHA, RGB, ARGB) * [toxi 050728] */ function buildBlurKernel(r) { var radius = (r * 3.5)|0; radius = (radius < 1) ? 1 : ((radius < 248) ? radius : 248); if (blurRadius !== radius) { blurRadius = radius; blurKernelSize = 1 + blurRadius<<1; blurKernel = new Int32Array(blurKernelSize); blurMult = new Array(blurKernelSize); for(var l = 0; l < blurKernelSize; l++){ blurMult[l] = new Int32Array(256); } var bk,bki; var bm,bmi; for (var i = 1, radiusi = radius - 1; i < radius; i++) { blurKernel[radius+i] = blurKernel[radiusi] = bki = radiusi * radiusi; bm = blurMult[radius+i]; bmi = blurMult[radiusi--]; for (var j = 0; j < 256; j++){ bm[j] = bmi[j] = bki * j; } } bk = blurKernel[radius] = radius * radius; bm = blurMult[radius]; for (var k = 0; k < 256; k++){ bm[k] = bk * k; } } } // Port of https://github.com/processing/processing/blob/ // master/core/src/processing/core/PImage.java#L1433 function blurARGB(canvas, radius) { var pixels = Filters._toPixels(canvas); var width = canvas.width; var height = canvas.height; var numPackedPixels = width * height; var argb = new Int32Array(numPackedPixels); for (var j = 0; j < numPackedPixels; j++) { argb[j] = Filters._getARGB(pixels, j); } var sum, cr, cg, cb, ca; var read, ri, ym, ymi, bk0; var a2 = new Int32Array(numPackedPixels); var r2 = new Int32Array(numPackedPixels); var g2 = new Int32Array(numPackedPixels); var b2 = new Int32Array(numPackedPixels); var yi = 0; buildBlurKernel(radius); var x, y, i; var bm; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { cb = cg = cr = ca = sum = 0; read = x - blurRadius; if (read < 0) { bk0 = -read; read = 0; } else { if (read >= width) { break; } bk0 = 0; } for (i = bk0; i < blurKernelSize; i++) { if (read >= width) { break; } var c = argb[read + yi]; bm = blurMult[i]; ca += bm[(c & -16777216) >>> 24]; cr += bm[(c & 16711680) >> 16]; cg += bm[(c & 65280) >> 8]; cb += bm[c & 255]; sum += blurKernel[i]; read++; } ri = yi + x; a2[ri] = ca / sum; r2[ri] = cr / sum; g2[ri] = cg / sum; b2[ri] = cb / sum; } yi += width; } yi = 0; ym = -blurRadius; ymi = ym * width; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { cb = cg = cr = ca = sum = 0; if (ym < 0) { bk0 = ri = -ym; read = x; } else { if (ym >= height) { break; } bk0 = 0; ri = ym; read = x + ymi; } for (i = bk0; i < blurKernelSize; i++) { if (ri >= height) { break; } bm = blurMult[i]; ca += bm[a2[read]]; cr += bm[r2[read]]; cg += bm[g2[read]]; cb += bm[b2[read]]; sum += blurKernel[i]; ri++; read += width; } argb[x + yi] = (ca/sum)<<24 | (cr/sum)<<16 | (cg/sum)<<8 | (cb/sum); } yi += width; ymi += width; ym++; } Filters._setPixels(pixels, argb); } Filters.blur = function(canvas, radius){ blurARGB(canvas, radius); }; module.exports = Filters; },{}],20:[function(_dereq_,module,exports){ /** * @module Math * @submodule Calculation * @for p5 * @requires core */ 'use strict'; var p5 = _dereq_('../core/core'); /** * Calculates the absolute value (magnitude) of a number. Maps to Math.abs(). * The absolute value of a number is always positive. * * @method abs * @param {Number} n number to compute * @return {Number} absolute value of given number * @example *
* function setup() { * var x = -3; * var y = abs(x); * * print(x); // -3 * print(y); // 3 * } *
* * @alt * no image displayed * */ p5.prototype.abs = Math.abs; /** * Calculates the closest int value that is greater than or equal to the * value of the parameter. Maps to Math.ceil(). For example, ceil(9.03) * returns the value 10. * * @method ceil * @param {Number} n number to round up * @return {Number} rounded up number * @example *
* function draw() { * background(200); * // map, mouseX between 0 and 5. * var ax = map(mouseX, 0, 100, 0, 5); * var ay = 66; * * //Get the ceiling of the mapped number. * var bx = ceil(map(mouseX, 0, 100, 0,5)); * var by = 33; * * // Multiply the mapped numbers by 20 to more easily * // see the changes. * stroke(0); * fill(0); * line(0, ay, ax * 20, ay); * line(0, by, bx * 20, by); * * // Reformat the float returned by map and draw it. * noStroke(); * text(nfc(ax, 2,2), ax, ay - 5); * text(nfc(bx,1,1), bx, by - 5); * } *
* * @alt * 2 horizontal lines & number sets. increase with mouse x. bottom to 2 decimals * */ p5.prototype.ceil = Math.ceil; /** * Constrains a value between a minimum and maximum value. * * @method constrain * @param {Number} n number to constrain * @param {Number} low minimum limit * @param {Number} high maximum limit * @return {Number} constrained number * @example *
* function draw() { * background(200); * * var leftWall = 25; * var rightWall = 75; * * // xm is just the mouseX, while * // xc is the mouseX, but constrained * // between the leftWall and rightWall! * var xm = mouseX; * var xc = constrain(mouseX, leftWall, rightWall); * * // Draw the walls. * stroke(150); * line(leftWall, 0, leftWall, height); * line(rightWall, 0, rightWall, height); * * // Draw xm and xc as circles. * noStroke(); * fill(150); * ellipse(xm, 33, 9,9); // Not Constrained * fill(0); * ellipse(xc, 66, 9,9); // Constrained * } *
* * @alt * 2 vertical lines. 2 ellipses move with mouse X 1 does not move passed lines * */ p5.prototype.constrain = function(n, low, high) { return Math.max(Math.min(n, high), low); }; /** * Calculates the distance between two points. * * @method dist * @param {Number} x1 x-coordinate of the first point * @param {Number} y1 y-coordinate of the first point * @param {Number} x2 x-coordinate of the second point * @param {Number} y2 y-coordinate of the second point * @return {Number} distance between the two points */ /** * @method dist * @param {Number} x1 * @param {Number} y1 * @param {Number} z1 z-coordinate of the first point * @param {Number} x2 * @param {Number} y2 * @param {Number} z2 z-coordinate of the second point * @return {Number} distance between the two points * @example *
* // Move your mouse inside the canvas to see the * // change in distance between two points! * function draw() { * background(200); * fill(0); * * var x1 = 10; * var y1 = 90; * var x2 = mouseX; * var y2 = mouseY; * * line(x1, y1, x2, y2); * ellipse(x1, y1, 7, 7); * ellipse(x2, y2, 7, 7); * * // d is the length of the line * // the distance from point 1 to point 2. * var d = int(dist(x1, y1, x2, y2)); * * // Let's write d along the line we are drawing! * push(); * translate( (x1+x2)/2, (y1+y2)/2 ); * rotate( atan2(y2-y1,x2-x1) ); * text(nfc(d,1,1), 0, -5); * pop(); * // Fancy! * } *
* * @alt * 2 ellipses joined by line. 1 ellipse moves with mouse X&Y. Distance displayed. * */ p5.prototype.dist = function(x1, y1, z1, x2, y2, z2) { if (arguments.length === 4) { // In the case of 2d: z1 means x2 and x2 means y2 return hypot(z1-x1, x2-y1); } else if (arguments.length === 6) { return hypot(x2-x1, y2-y1, z2-z1); } }; /** * Returns Euler's number e (2.71828...) raised to the power of the n * parameter. Maps to Math.exp(). * * @method exp * @param {Number} n exponent to raise * @return {Number} e^n * @example *
* function draw() { * background(200); * * // Compute the exp() function with a value between 0 and 2 * var xValue = map(mouseX, 0, width, 0, 2); * var yValue = exp(xValue); * * var y = map(yValue, 0, 8, height, 0); * * var legend = "exp (" + nfc(xValue, 3) +")\n= " + nf(yValue, 1, 4); * stroke(150); * line(mouseX, y, mouseX, height); * fill(0); * text(legend, 5, 15); * noStroke(); * ellipse (mouseX,y, 7, 7); * * // Draw the exp(x) curve, * // over the domain of x from 0 to 2 * noFill(); * stroke(0); * beginShape(); * for (var x = 0; x < width; x++) { * xValue = map(x, 0, width, 0, 2); * yValue = exp(xValue); * y = map(yValue, 0, 8, height, 0); * vertex(x, y); * } * * endShape(); * line(0, 0, 0, height); * line(0, height-1, width, height-1); * } *
* * @alt * ellipse moves along a curve with mouse x. e^n displayed. * */ p5.prototype.exp = Math.exp; /** * Calculates the closest int value that is less than or equal to the * value of the parameter. Maps to Math.floor(). * * @method floor * @param {Number} n number to round down * @return {Number} rounded down number * @example *
* function draw() { * background(200); * //map, mouseX between 0 and 5. * var ax = map(mouseX, 0, 100, 0, 5); * var ay = 66; * * //Get the floor of the mapped number. * var bx = floor(map(mouseX, 0, 100, 0,5)); * var by = 33; * * // Multiply the mapped numbers by 20 to more easily * // see the changes. * stroke(0); * fill(0); * line(0, ay, ax * 20, ay); * line(0, by, bx * 20, by); * * // Reformat the float returned by map and draw it. * noStroke(); * text(nfc(ax, 2,2), ax, ay - 5); * text(nfc(bx,1,1), bx, by - 5); * } *
* * @alt * 2 horizontal lines & number sets. increase with mouse x. bottom to 2 decimals * */ p5.prototype.floor = Math.floor; /** * Calculates a number between two numbers at a specific increment. The amt * parameter is the amount to interpolate between the two values where 0.0 * equal to the first point, 0.1 is very near the first point, 0.5 is * half-way in between, etc. The lerp function is convenient for creating * motion along a straight path and for drawing dotted lines. * * @method lerp * @param {Number} start first value * @param {Number} stop second value * @param {Number} amt number between 0.0 and 1.0 * @return {Number} lerped value * @example *
* function setup() { * background(200); * var a = 20; * var b = 80; * var c = lerp(a,b, .2); * var d = lerp(a,b, .5); * var e = lerp(a,b, .8); * * var y = 50 * * strokeWeight(5); * stroke(0); // Draw the original points in black * point(a, y); * point(b, y); * * stroke(100); // Draw the lerp points in gray * point(c, y); * point(d, y); * point(e, y); * } *
* * @alt * 5 points horizontally staggered mid-canvas. mid 3 are grey, outer black * */ p5.prototype.lerp = function(start, stop, amt) { return amt*(stop-start)+start; }; /** * Calculates the natural logarithm (the base-e logarithm) of a number. This * function expects the n parameter to be a value greater than 0.0. Maps to * Math.log(). * * @method log * @param {Number} n number greater than 0 * @return {Number} natural logarithm of n * @example *
* function draw() { * background(200); * var maxX = 2.8; * var maxY = 1.5; * * // Compute the natural log of a value between 0 and maxX * var xValue = map(mouseX, 0, width, 0, maxX); * if (xValue > 0) { // Cannot take the log of a negative number. * var yValue = log(xValue); * var y = map(yValue, -maxY, maxY, height, 0); * * // Display the calculation occurring. * var legend = "log(" + nf(xValue, 1, 2) + ")\n= " + nf(yValue, 1, 3); * stroke(150); * line(mouseX, y, mouseX, height); * fill(0); * text (legend, 5, 15); * noStroke(); * ellipse (mouseX, y, 7, 7); * } * * // Draw the log(x) curve, * // over the domain of x from 0 to maxX * noFill(); * stroke(0); * beginShape(); * for(var x=0; x < width; x++) { * xValue = map(x, 0, width, 0, maxX); * yValue = log(xValue); * y = map(yValue, -maxY, maxY, height, 0); * vertex(x, y); * } * endShape(); * line(0,0,0,height); * line(0,height/2,width, height/2); * } *
* * @alt * ellipse moves along a curve with mouse x. natural logarithm of n displayed. * */ p5.prototype.log = Math.log; /** * Calculates the magnitude (or length) of a vector. A vector is a direction * in space commonly used in computer graphics and linear algebra. Because it * has no "start" position, the magnitude of a vector can be thought of as * the distance from the coordinate 0,0 to its x,y value. Therefore, mag() is * a shortcut for writing dist(0, 0, x, y). * * @method mag * @param {Number} a first value * @param {Number} b second value * @return {Number} magnitude of vector from (0,0) to (a,b) * @example *
* function setup() { * var x1 = 20; * var x2 = 80; * var y1 = 30; * var y2 = 70; * * line(0, 0, x1, y1); * print(mag(x1, y1)); // Prints "36.05551275463989" * line(0, 0, x2, y1); * print(mag(x2, y1)); // Prints "85.44003745317531" * line(0, 0, x1, y2); * print(mag(x1, y2)); // Prints "72.80109889280519" * line(0, 0, x2, y2); * print(mag(x2, y2)); // Prints "106.3014581273465" * } *
* * @alt * 4 lines of different length radiate from top left of canvas. * */ p5.prototype.mag = function(x, y) { return hypot(x, y); }; /** * Re-maps a number from one range to another. *

* In the first example above, the number 25 is converted from a value in the * range of 0 to 100 into a value that ranges from the left edge of the * window (0) to the right edge (width). * * @method map * @param {Number} value the incoming value to be converted * @param {Number} start1 lower bound of the value's current range * @param {Number} stop1 upper bound of the value's current range * @param {Number} start2 lower bound of the value's target range * @param {Number} stop2 upper bound of the value's target range * @return {Number} remapped number * @example *
* var value = 25; * var m = map(value, 0, 100, 0, width); * ellipse(m, 50, 10, 10); *
* *
* function setup() { * noStroke(); * } * * function draw() { * background(204); * var x1 = map(mouseX, 0, width, 25, 75); * ellipse(x1, 25, 25, 25); * var x2 = map(mouseX, 0, width, 0, 100); * ellipse(x2, 75, 25, 25); * } *
* * @alt * 10 by 10 white ellipse with in mid left canvas * 2 25 by 25 white ellipses move with mouse x. Bottom has more range from X * */ p5.prototype.map = function(n, start1, stop1, start2, stop2) { return ((n-start1)/(stop1-start1))*(stop2-start2)+start2; }; /** * Determines the largest value in a sequence of numbers, and then returns * that value. max() accepts any number of Number parameters, or an Array * of any length. * * @method max * @param {Number|Array} n0 Numbers to compare * @return {Number} maximum Number * @example *
* function setup() { * // Change the elements in the array and run the sketch * // to show how max() works! * numArray = new Array(2,1,5,4,8,9); * fill(0); * noStroke(); * text("Array Elements", 0, 10); * // Draw all numbers in the array * var spacing = 15; * var elemsY = 25; * for(var i = 0; i < numArray.length; i++) { * text(numArray[i], i * spacing, elemsY); * } * maxX = 33; * maxY = 80; * // Draw the Maximum value in the array. * textSize(32); * text(max(numArray), maxX, maxY); * } *
* * @alt * Small text at top reads: Array Elements 2 1 5 4 8 9. Large text at center: 9 * */ p5.prototype.max = function() { if (arguments[0] instanceof Array) { return Math.max.apply(null,arguments[0]); } else { return Math.max.apply(null,arguments); } }; /** * Determines the smallest value in a sequence of numbers, and then returns * that value. min() accepts any number of Number parameters, or an Array * of any length. * * @method min * @param {Number|Array} n0 Numbers to compare * @return {Number} minimum Number * @example *
* function setup() { * // Change the elements in the array and run the sketch * // to show how min() works! * numArray = new Array(2,1,5,4,8,9); * fill(0); * noStroke(); * text("Array Elements", 0, 10); * // Draw all numbers in the array * var spacing = 15; * var elemsY = 25; * for(var i = 0; i < numArray.length; i++) { * text(numArray[i], i * spacing, elemsY); * } * maxX = 33; * maxY = 80; * // Draw the Minimum value in the array. * textSize(32); * text(min(numArray), maxX, maxY); * } *
* * @alt * Small text at top reads: Array Elements 2 1 5 4 8 9. Large text at center: 1 * */ p5.prototype.min = function() { if (arguments[0] instanceof Array) { return Math.min.apply(null,arguments[0]); } else { return Math.min.apply(null,arguments); } }; /** * Normalizes a number from another range into a value between 0 and 1. * Identical to map(value, low, high, 0, 1). * Numbers outside of the range are not clamped to 0 and 1, because * out-of-range values are often intentional and useful. (See the second * example above.) * * @method norm * @param {Number} value incoming value to be normalized * @param {Number} start lower bound of the value's current range * @param {Number} stop upper bound of the value's current range * @return {Number} normalized number * @example *
* function draw() { * background(200); * currentNum = mouseX; * lowerBound = 0; * upperBound = width; //100; * normalized = norm(currentNum, lowerBound, upperBound); * lineY = 70 * line(0, lineY, width, lineY); * //Draw an ellipse mapped to the non-normalized value. * noStroke(); * fill(50) * var s = 7; // ellipse size * ellipse(currentNum, lineY, s, s); * * // Draw the guide * guideY = lineY + 15; * text("0", 0, guideY); * textAlign(RIGHT); * text("100", width, guideY); * * // Draw the normalized value * textAlign(LEFT); * fill(0); * textSize(32); * normalY = 40; * normalX = 20; * text(normalized, normalX, normalY); * } *
* * @alt * ellipse moves with mouse. 0 shown left & 100 right and updating values center * */ p5.prototype.norm = function(n, start, stop) { return this.map(n, start, stop, 0, 1); }; /** * Facilitates exponential expressions. The pow() function is an efficient * way of multiplying numbers by themselves (or their reciprocals) in large * quantities. For example, pow(3, 5) is equivalent to the expression * 3*3*3*3*3 and pow(3, -5) is equivalent to 1 / 3*3*3*3*3. Maps to * Math.pow(). * * @method pow * @param {Number} n base of the exponential expression * @param {Number} e power by which to raise the base * @return {Number} n^e * @example *
* function setup() { * //Exponentially increase the size of an ellipse. * eSize = 3; // Original Size * eLoc = 10; // Original Location * * ellipse(eLoc, eLoc, eSize, eSize); * * ellipse(eLoc*2, eLoc*2, pow(eSize, 2), pow(eSize, 2)); * * ellipse(eLoc*4, eLoc*4, pow(eSize, 3), pow(eSize, 3)); * * ellipse(eLoc*8, eLoc*8, pow(eSize, 4), pow(eSize, 4)); * } *
* * @alt * small to large ellipses radiating from top left of canvas * */ p5.prototype.pow = Math.pow; /** * Calculates the integer closest to the n parameter. For example, * round(133.8) returns the value 134. Maps to Math.round(). * * @method round * @param {Number} n number to round * @return {Number} rounded number * @example *
* function draw() { * background(200); * //map, mouseX between 0 and 5. * var ax = map(mouseX, 0, 100, 0, 5); * var ay = 66; * * // Round the mapped number. * var bx = round(map(mouseX, 0, 100, 0,5)); * var by = 33; * * // Multiply the mapped numbers by 20 to more easily * // see the changes. * stroke(0); * fill(0); * line(0, ay, ax * 20, ay); * line(0, by, bx * 20, by); * * // Reformat the float returned by map and draw it. * noStroke(); * text(nfc(ax, 2,2), ax, ay - 5); * text(nfc(bx,1,1), bx, by - 5); * } *
* * @alt * horizontal center line squared values displayed on top and regular on bottom. * */ p5.prototype.round = Math.round; /** * Squares a number (multiplies a number by itself). The result is always a * positive number, as multiplying two negative numbers always yields a * positive result. For example, -1 * -1 = 1. * * @method sq * @param {Number} n number to square * @return {Number} squared number * @example *
* function draw() { * background(200); * eSize = 7; * x1 = map(mouseX, 0, width, 0, 10); * y1 = 80; * x2 = sq(x1); * y2 = 20; * * // Draw the non-squared. * line(0, y1, width, y1); * ellipse(x1, y1, eSize, eSize); * * // Draw the squared. * line(0, y2, width, y2); * ellipse(x2, y2, eSize, eSize); * * // Draw dividing line. * stroke(100) * line(0, height/2, width, height/2); * * // Draw text. * var spacing = 15; * noStroke(); * fill(0); * text("x = " + x1, 0, y1 + spacing); * text("sq(x) = " + x2, 0, y2 + spacing); * } *
* * @alt * horizontal center line squared values displayed on top and regular on bottom. * */ p5.prototype.sq = function(n) { return n*n; }; /** * Calculates the square root of a number. The square root of a number is * always positive, even though there may be a valid negative root. The * square root s of number a is such that s*s = a. It is the opposite of * squaring. Maps to Math.sqrt(). * * @method sqrt * @param {Number} n non-negative number to square root * @return {Number} square root of number * @example *
* function draw() { * background(200); * eSize = 7; * x1 = mouseX; * y1 = 80; * x2 = sqrt(x1); * y2 = 20; * * // Draw the non-squared. * line(0, y1, width, y1); * ellipse(x1, y1, eSize, eSize); * * // Draw the squared. * line(0, y2, width, y2); * ellipse(x2, y2, eSize, eSize); * * // Draw dividing line. * stroke(100) * line(0, height/2, width, height/2); * * // Draw text. * noStroke(); * fill(0); * var spacing = 15; * text("x = " + x1, 0, y1 + spacing); * text("sqrt(x) = " + x2, 0, y2 + spacing); * } *
* * @alt * horizontal center line squareroot values displayed on top and regular on bottom. * */ p5.prototype.sqrt = Math.sqrt; // Calculate the length of the hypotenuse of a right triangle // This won't under- or overflow in intermediate steps // https://en.wikipedia.org/wiki/Hypot function hypot(x, y, z) { // Use the native implementation if it's available if (typeof Math.hypot === 'function') { return Math.hypot.apply(null, arguments); } // Otherwise use the V8 implementation // https://github.com/v8/v8/blob/8cd3cf297287e581a49e487067f5cbd991b27123/src/js/math.js#L217 var length = arguments.length; var args = []; var max = 0; for (var i = 0; i < length; i++) { var n = arguments[i]; n = +n; if (n === Infinity || n === -Infinity) { return Infinity; } n = Math.abs(n); if (n > max) { max = n; } args[i] = n; } if (max === 0) { max = 1; } var sum = 0; var compensation = 0; for (var j = 0; j < length; j++) { var m = args[j] / max; var summand = m * m - compensation; var preliminary = sum + summand; compensation = (preliminary - sum) - summand; sum = preliminary; } return Math.sqrt(sum) * max; } module.exports = p5; },{"../core/core":5}],21:[function(_dereq_,module,exports){ /** * @module Math * @submodule Math * @for p5 * @requires core */ 'use strict'; var p5 = _dereq_('../core/core'); /** * Creates a new p5.Vector (the datatype for storing vectors). This provides a * two or three dimensional vector, specifically a Euclidean (also known as * geometric) vector. A vector is an entity that has both magnitude and * direction. * * @method createVector * @param {Number} [x] x component of the vector * @param {Number} [y] y component of the vector * @param {Number} [z] z component of the vector * @return {p5.Vector} */ p5.prototype.createVector = function (x, y, z) { if (this instanceof p5) { return new p5.Vector(this, arguments); } else { return new p5.Vector(x, y, z); } }; module.exports = p5; },{"../core/core":5}],22:[function(_dereq_,module,exports){ ////////////////////////////////////////////////////////////// // http://mrl.nyu.edu/~perlin/noise/ // Adapting from PApplet.java // which was adapted from toxi // which was adapted from the german demo group farbrausch // as used in their demo "art": http://www.farb-rausch.de/fr010src.zip // someday we might consider using "improved noise" // http://mrl.nyu.edu/~perlin/paper445.pdf // See: https://github.com/shiffman/The-Nature-of-Code-Examples-p5.js/ // blob/master/introduction/Noise1D/noise.js /** * @module Math * @submodule Noise * @for p5 * @requires core */ 'use strict'; var p5 = _dereq_('../core/core'); var PERLIN_YWRAPB = 4; var PERLIN_YWRAP = 1<random() function. * It was invented by Ken Perlin in the 1980s and been used since in * graphical applications to produce procedural textures, natural motion, * shapes, terrains etc.

The main difference to the * random() function is that Perlin noise is defined in an infinite * n-dimensional space where each pair of coordinates corresponds to a * fixed semi-random value (fixed only for the lifespan of the program; see * the noiseSeed() function). p5.js can compute 1D, 2D and 3D noise, * depending on the number of coordinates given. The resulting value will * always be between 0.0 and 1.0. The noise value can be animated by moving * through the noise space as demonstrated in the example above. The 2nd * and 3rd dimension can also be interpreted as time.

The actual * noise is structured similar to an audio signal, in respect to the * function's use of frequencies. Similar to the concept of harmonics in * physics, perlin noise is computed over several octaves which are added * together for the final result.

Another way to adjust the * character of the resulting sequence is the scale of the input * coordinates. As the function works within an infinite space the value of * the coordinates doesn't matter as such, only the distance between * successive coordinates does (eg. when using noise() within a * loop). As a general rule the smaller the difference between coordinates, * the smoother the resulting noise sequence will be. Steps of 0.005-0.03 * work best for most applications, but this will differ depending on use. * * * @method noise * @param {Number} x x-coordinate in noise space * @param {Number} [y] y-coordinate in noise space * @param {Number} [z] z-coordinate in noise space * @return {Number} Perlin noise value (between 0 and 1) at specified * coordinates * @example *
* var xoff = 0.0; * * function draw() { * background(204); * xoff = xoff + .01; * var n = noise(xoff) * width; * line(n, 0, n, height); * } * *
*
* var noiseScale=0.02; * * function draw() { * background(0); * for (var x=0; x < width; x++) { * var noiseVal = noise((mouseX+x)*noiseScale, mouseY*noiseScale); * stroke(noiseVal*255); * line(x, mouseY+noiseVal*80, x, height); * } * } * *
* * @alt * vertical line moves left to right with updating noise values. * horizontal wave pattern effected by mouse x-position & updating noise values. * */ p5.prototype.noise = function(x,y,z) { y = y || 0; z = z || 0; if (perlin == null) { perlin = new Array(PERLIN_SIZE + 1); for (var i = 0; i < PERLIN_SIZE + 1; i++) { perlin[i] = Math.random(); } } if (x<0) { x=-x; } if (y<0) { y=-y; } if (z<0) { z=-z; } var xi=Math.floor(x), yi=Math.floor(y), zi=Math.floor(z); var xf = x - xi; var yf = y - yi; var zf = z - zi; var rxf, ryf; var r=0; var ampl=0.5; var n1,n2,n3; for (var o=0; o=1.0) { xi++; xf--; } if (yf>=1.0) { yi++; yf--; } if (zf>=1.0) { zi++; zf--; } } return r; }; /** * * Adjusts the character and level of detail produced by the Perlin noise * function. Similar to harmonics in physics, noise is computed over * several octaves. Lower octaves contribute more to the output signal and * as such define the overall intensity of the noise, whereas higher octaves * create finer grained details in the noise sequence. *

* By default, noise is computed over 4 octaves with each octave contributing * exactly half than its predecessor, starting at 50% strength for the 1st * octave. This falloff amount can be changed by adding an additional function * parameter. Eg. a falloff factor of 0.75 means each octave will now have * 75% impact (25% less) of the previous lower octave. Any value between * 0.0 and 1.0 is valid, however note that values greater than 0.5 might * result in greater than 1.0 values returned by noise(). *

* By changing these parameters, the signal created by the noise() * function can be adapted to fit very specific needs and characteristics. * * @method noiseDetail * @param {Number} lod number of octaves to be used by the noise * @param {Number} falloff falloff factor for each octave * @example *
* * * var noiseVal; * var noiseScale=0.02; * * function setup() { * createCanvas(100,100); * } * * function draw() { * background(0); * for (var y = 0; y < height; y++) { * for (var x = 0; x < width/2; x++) { * noiseDetail(2,0.2); * noiseVal = noise((mouseX+x) * noiseScale, * (mouseY+y) * noiseScale); * stroke(noiseVal*255); * point(x,y); * noiseDetail(8,0.65); * noiseVal = noise((mouseX + x + width/2) * noiseScale, * (mouseY + y) * noiseScale); * stroke(noiseVal*255); * point(x + width/2, y); * } * } * } * *
* * @alt * 2 vertical grey smokey patterns affected my mouse x-position and noise. * */ p5.prototype.noiseDetail = function(lod, falloff) { if (lod>0) { perlin_octaves=lod; } if (falloff>0) { perlin_amp_falloff=falloff; } }; /** * Sets the seed value for noise(). By default, noise() * produces different results each time the program is run. Set the * value parameter to a constant to return the same pseudo-random * numbers each time the software is run. * * @method noiseSeed * @param {Number} seed the seed value * @example *
* var xoff = 0.0; * * function setup() { * noiseSeed(99); * stroke(0, 10); * } * * function draw() { * xoff = xoff + .01; * var n = noise(xoff) * width; * line(n, 0, n, height); * } * *
* * @alt * vertical grey lines drawing in pattern affected by noise. * */ p5.prototype.noiseSeed = function(seed) { // Linear Congruential Generator // Variant of a Lehman Generator var lcg = (function() { // Set to values from http://en.wikipedia.org/wiki/Numerical_Recipes // m is basically chosen to be large (as it is the max period) // and for its relationships to a and c var m = 4294967296, // a - 1 should be divisible by m's prime factors a = 1664525, // c and m should be co-prime c = 1013904223, seed, z; return { setSeed : function(val) { // pick a random seed if val is undefined or null // the >>> 0 casts the seed to an unsigned 32-bit integer z = seed = (val == null ? Math.random() * m : val) >>> 0; }, getSeed : function() { return seed; }, rand : function() { // define the recurrence relationship z = (a * z + c) % m; // return a float in [0, 1) // if z = m then z / m = 0 therefore (z % m) / m < 1 always return z / m; } }; }()); lcg.setSeed(seed); perlin = new Array(PERLIN_SIZE + 1); for (var i = 0; i < PERLIN_SIZE + 1; i++) { perlin[i] = lcg.rand(); } }; module.exports = p5; },{"../core/core":5}],23:[function(_dereq_,module,exports){ /** * @module Math * @submodule Math * @requires constants */ 'use strict'; var p5 = _dereq_('../core/core'); var polarGeometry = _dereq_('./polargeometry'); var constants = _dereq_('../core/constants'); /** * A class to describe a two or three dimensional vector, specifically * a Euclidean (also known as geometric) vector. A vector is an entity * that has both magnitude and direction. The datatype, however, stores * the components of the vector (x, y for 2D, and x, y, z for 3D). The magnitude * and direction can be accessed via the methods mag() and heading(). *

* In many of the p5.js examples, you will see p5.Vector used to describe a * position, velocity, or acceleration. For example, if you consider a rectangle * moving across the screen, at any given instant it has a position (a vector * that points from the origin to its location), a velocity (the rate at which * the object's position changes per time unit, expressed as a vector), and * acceleration (the rate at which the object's velocity changes per time * unit, expressed as a vector). *

* Since vectors represent groupings of values, we cannot simply use * traditional addition/multiplication/etc. Instead, we'll need to do some * "vector" math, which is made easy by the methods inside the p5.Vector class. * * @class p5.Vector * @constructor * @param {Number} [x] x component of the vector * @param {Number} [y] y component of the vector * @param {Number} [z] z component of the vector * @example *
* * var v1 = createVector(40, 50); * var v2 = createVector(40, 50); * * ellipse(v1.x, v1.y, 50, 50); * ellipse(v2.x, v2.y, 50, 50); * v1.add(v2); * ellipse(v1.x, v1.y, 50, 50); * *
* * @alt * 2 white ellipses. One center-left the other bottom right and off canvas * */ p5.Vector = function() { var x,y,z; // This is how it comes in with createVector() if(arguments[0] instanceof p5) { // save reference to p5 if passed in this.p5 = arguments[0]; x = arguments[1][0] || 0; y = arguments[1][1] || 0; z = arguments[1][2] || 0; // This is what we'll get with new p5.Vector() } else { x = arguments[0] || 0; y = arguments[1] || 0; z = arguments[2] || 0; } /** * The x component of the vector * @property x {Number} */ this.x = x; /** * The y component of the vector * @property y {Number} */ this.y = y; /** * The z component of the vector * @property z {Number} */ this.z = z; }; /** * Returns a string representation of a vector v by calling String(v) * or v.toString(). This method is useful for logging vectors in the * console. * @method toString * @example *
* function setup() { * var v = createVector(20,30); * print(String(v)); // prints "p5.Vector Object : [20, 30, 0]" * } *
* */ p5.Vector.prototype.toString = function p5VectorToString() { return 'p5.Vector Object : ['+ this.x +', '+ this.y +', '+ this.z + ']'; }; /** * Sets the x, y, and z component of the vector using two or three separate * variables, the data from a p5.Vector, or the values from a float array. * @method set * @param {Number|p5.Vector|Array} [x] the x component of the vector or a * p5.Vector or an Array * @param {Number} [y] the y component of the vector * @param {Number} [z] the z component of the vector * @chainable * @example *
* * function setup() { * var v = createVector(1, 2, 3); * v.set(4,5,6); // Sets vector to [4, 5, 6] * * var v1 = createVector(0, 0, 0); * var arr = [1, 2, 3]; * v1.set(arr); // Sets vector to [1, 2, 3] * } * *
*/ p5.Vector.prototype.set = function (x, y, z) { if (x instanceof p5.Vector) { this.x = x.x || 0; this.y = x.y || 0; this.z = x.z || 0; return this; } if (x instanceof Array) { this.x = x[0] || 0; this.y = x[1] || 0; this.z = x[2] || 0; return this; } this.x = x || 0; this.y = y || 0; this.z = z || 0; return this; }; /** * Gets a copy of the vector, returns a p5.Vector object. * * @method copy * @return {p5.Vector} the copy of the p5.Vector object * @example *
* * var v1 = createVector(1, 2, 3); * var v2 = v1.copy(); * print(v1.x == v2.x && v1.y == v2.y && v1.z == v2.z); * // Prints "true" * *
*/ p5.Vector.prototype.copy = function () { if (this.p5) { return new p5.Vector(this.p5,[this.x, this.y, this.z]); } else { return new p5.Vector(this.x,this.y,this.z); } }; /** * Adds x, y, and z components to a vector, adds one vector to another, or * adds two independent vectors together. The version of the method that adds * two vectors together is a static method and returns a p5.Vector, the others * acts directly on the vector. See the examples for more context. * * @method add * @param {Number|p5.Vector|Array} x the x component of the vector to be * added or a p5.Vector or an Array * @param {Number} [y] the y component of the vector to be * added * @param {Number} [z] the z component of the vector to be * added * @chainable * @example *
* * var v = createVector(1, 2, 3); * v.add(4,5,6); * // v's components are set to [5, 7, 9] * *
*
* * // Static method * var v1 = createVector(1, 2, 3); * var v2 = createVector(2, 3, 4); * * var v3 = p5.Vector.add(v1, v2); * // v3 has components [3, 5, 7] * *
*/ p5.Vector.prototype.add = function (x, y, z) { if (x instanceof p5.Vector) { this.x += x.x || 0; this.y += x.y || 0; this.z += x.z || 0; return this; } if (x instanceof Array) { this.x += x[0] || 0; this.y += x[1] || 0; this.z += x[2] || 0; return this; } this.x += x || 0; this.y += y || 0; this.z += z || 0; return this; }; /** * Subtracts x, y, and z components from a vector, subtracts one vector from * another, or subtracts two independent vectors. The version of the method * that subtracts two vectors is a static method and returns a p5.Vector, the * other acts directly on the vector. See the examples for more context. * * @method sub * @param {Number|p5.Vector|Array} x the x component of the vector or a * p5.Vector or an Array * @param {Number} [y] the y component of the vector * @param {Number} [z] the z component of the vector * @chainable * @example *
* * var v = createVector(4, 5, 6); * v.sub(1, 1, 1); * // v's components are set to [3, 4, 5] * *
* *
* * // Static method * var v1 = createVector(2, 3, 4); * var v2 = createVector(1, 2, 3); * * var v3 = p5.Vector.sub(v1, v2); * // v3 has components [1, 1, 1] * *
*/ p5.Vector.prototype.sub = function (x, y, z) { if (x instanceof p5.Vector) { this.x -= x.x || 0; this.y -= x.y || 0; this.z -= x.z || 0; return this; } if (x instanceof Array) { this.x -= x[0] || 0; this.y -= x[1] || 0; this.z -= x[2] || 0; return this; } this.x -= x || 0; this.y -= y || 0; this.z -= z || 0; return this; }; /** * Multiply the vector by a scalar. The static version of this method * creates a new p5.Vector while the non static version acts on the vector * directly. See the examples for more context. * * @method mult * @param {Number} n the number to multiply with the vector * @chainable * @example *
* * var v = createVector(1, 2, 3); * v.mult(2); * // v's components are set to [2, 4, 6] * *
* *
* * // Static method * var v1 = createVector(1, 2, 3); * var v2 = p5.Vector.mult(v1, 2); * // v2 has components [2, 4, 6] * *
*/ p5.Vector.prototype.mult = function (n) { this.x *= n || 0; this.y *= n || 0; this.z *= n || 0; return this; }; /** * Divide the vector by a scalar. The static version of this method creates a * new p5.Vector while the non static version acts on the vector directly. * See the examples for more context. * * @method div * @param {number} n the number to divide the vector by * @chainable * @example *
* * var v = createVector(6, 4, 2); * v.div(2); //v's components are set to [3, 2, 1] * *
* *
* * // Static method * var v1 = createVector(6, 4, 2); * var v2 = p5.Vector.div(v, 2); * // v2 has components [3, 2, 1] * *
*/ p5.Vector.prototype.div = function (n) { this.x /= n; this.y /= n; this.z /= n; return this; }; /** * Calculates the magnitude (length) of the vector and returns the result as * a float (this is simply the equation sqrt(x*x + y*y + z*z).) * * @method mag * @return {Number} magnitude of the vector * @example *
* * var v = createVector(20.0, 30.0, 40.0); * var m = v.mag(); * print(m); // Prints "53.85164807134504" * *
*/ p5.Vector.prototype.mag = function () { return Math.sqrt(this.magSq()); }; /** * Calculates the squared magnitude of the vector and returns the result * as a float (this is simply the equation (x*x + y*y + z*z).) * Faster if the real length is not required in the * case of comparing vectors, etc. * * @method magSq * @return {number} squared magnitude of the vector * @example *
* * // Static method * var v1 = createVector(6, 4, 2); * print(v1.magSq()); // Prints "56" * *
*/ p5.Vector.prototype.magSq = function () { var x = this.x, y = this.y, z = this.z; return (x * x + y * y + z * z); }; /** * Calculates the dot product of two vectors. The version of the method * that computes the dot product of two independent vectors is a static * method. See the examples for more context. * * * @method dot * @param {Number|p5.Vector} x x component of the vector or a p5.Vector * @param {Number} [y] y component of the vector * @param {Number} [z] z component of the vector * @return {Number} the dot product * * @example *
* * var v1 = createVector(1, 2, 3); * var v2 = createVector(2, 3, 4); * * print(v1.dot(v2)); // Prints "20" * *
* *
* * //Static method * var v1 = createVector(1, 2, 3); * var v2 = createVector(3, 2, 1); * print (p5.Vector.dot(v1, v2)); // Prints "10" * *
*/ p5.Vector.prototype.dot = function (x, y, z) { if (x instanceof p5.Vector) { return this.dot(x.x, x.y, x.z); } return this.x * (x || 0) + this.y * (y || 0) + this.z * (z || 0); }; /** * Calculates and returns a vector composed of the cross product between * two vectors. Both the static and non static methods return a new p5.Vector. * See the examples for more context. * * @method cross * @param {p5.Vector} v p5.Vector to be crossed * @return {p5.Vector} p5.Vector composed of cross product * @example *
* * var v1 = createVector(1, 2, 3); * var v2 = createVector(1, 2, 3); * * v1.cross(v2); // v's components are [0, 0, 0] * *
* *
* * // Static method * var v1 = createVector(1, 0, 0); * var v2 = createVector(0, 1, 0); * * var crossProduct = p5.Vector.cross(v1, v2); * // crossProduct has components [0, 0, 1] * *
*/ p5.Vector.prototype.cross = function (v) { var x = this.y * v.z - this.z * v.y; var y = this.z * v.x - this.x * v.z; var z = this.x * v.y - this.y * v.x; if (this.p5) { return new p5.Vector(this.p5,[x,y,z]); } else { return new p5.Vector(x,y,z); } }; /** * Calculates the Euclidean distance between two points (considering a * point as a vector object). * * @method dist * @param {p5.Vector} v the x, y, and z coordinates of a p5.Vector * @return {Number} the distance * @example *
* * var v1 = createVector(1, 0, 0); * var v2 = createVector(0, 1, 0); * * var distance = v1.dist(v2); // distance is 1.4142... * *
*
* * // Static method * var v1 = createVector(1, 0, 0); * var v2 = createVector(0, 1, 0); * * var distance = p5.Vector.dist(v1,v2); * // distance is 1.4142... * *
*/ p5.Vector.prototype.dist = function (v) { var d = v.copy().sub(this); return d.mag(); }; /** * Normalize the vector to length 1 (make it a unit vector). * * @method normalize * @return {p5.Vector} normalized p5.Vector * @example *
* * var v = createVector(10, 20, 2); * // v has components [10.0, 20.0, 2.0] * v.normalize(); * // v's components are set to * // [0.4454354, 0.8908708, 0.089087084] * *
* */ p5.Vector.prototype.normalize = function () { return this.mag() === 0 ? this : this.div(this.mag()); }; /** * Limit the magnitude of this vector to the value used for the max * parameter. * * @method limit * @param {Number} max the maximum magnitude for the vector * @chainable * @example *
* * var v = createVector(10, 20, 2); * // v has components [10.0, 20.0, 2.0] * v.limit(5); * // v's components are set to * // [2.2271771, 4.4543543, 0.4454354] * *
*/ p5.Vector.prototype.limit = function (max) { var mSq = this.magSq(); if(mSq > max*max) { this.div(Math.sqrt(mSq)); //normalize it this.mult(max); } return this; }; /** * Set the magnitude of this vector to the value used for the len * parameter. * * @method setMag * @param {number} len the new length for this vector * @chainable * @example *
* * var v = createVector(10, 20, 2); * // v has components [10.0, 20.0, 2.0] * v.setMag(10); * // v's components are set to [6.0, 8.0, 0.0] * *
*/ p5.Vector.prototype.setMag = function (n) { return this.normalize().mult(n); }; /** * Calculate the angle of rotation for this vector (only 2D vectors) * * @method heading * @return {Number} the angle of rotation * @example *
* function setup() { * var v1 = createVector(30,50); * print(v1.heading()); // 1.0303768265243125 * * var v1 = createVector(40,50); * print(v1.heading()); // 0.8960553845713439 * * var v1 = createVector(30,70); * print(v1.heading()); // 1.1659045405098132 * } *
*/ p5.Vector.prototype.heading = function () { var h = Math.atan2(this.y, this.x); if (this.p5) { if (this.p5._angleMode === constants.RADIANS) { return h; } else { return polarGeometry.radiansToDegrees(h); } } else { return h; } }; /** * Rotate the vector by an angle (only 2D vectors), magnitude remains the * same * * @method rotate * @param {number} angle the angle of rotation * @chainable * @example *
* * var v = createVector(10.0, 20.0); * // v has components [10.0, 20.0, 0.0] * v.rotate(HALF_PI); * // v's components are set to [-20.0, 9.999999, 0.0] * *
*/ p5.Vector.prototype.rotate = function (a) { var newHeading = this.heading() + a; if (this.p5) { if (this.p5._angleMode === constants.DEGREES) { newHeading = polarGeometry.degreesToRadians(newHeading); } } var mag = this.mag(); this.x = Math.cos(newHeading) * mag; this.y = Math.sin(newHeading) * mag; return this; }; /** * Calculates and returns the angle (in radians) between two vectors. * @method angleBetween * @param {p5.Vector} the x, y, and z components of a p5.Vector * @return {Number} the angle between (in radians) * @example *
* * var v1 = createVector(1, 0, 0); * var v2 = createVector(0, 1, 0); * * var angle = v1.angleBetween(v2); * // angle is PI/2 * *
*/ p5.Vector.prototype.angleBetween = function (v) { var angle = Math.acos(this.dot(v) / (this.mag() * v.mag())); if (this.p5) { if (this.p5._angleMode === constants.DEGREES) { angle = polarGeometry.radiansToDegrees(angle); } } return angle; }; /** * Linear interpolate the vector to another vector * * @method lerp * @param {p5.Vector} x the x component * @param {p5.Vector} y the y component * @param {p5.Vector} z the z component * @param {Number} amt the amount of interpolation; some value between 0.0 * (old vector) and 1.0 (new vector). 0.1 is very near * the new vector. 0.5 is halfway in between. * @chainable */ /** * @method lerp * @param {p5.Vector} v the p5.Vector to lerp to * @param {Number} amt * @chainable * * @example *
* * var v = createVector(1, 1, 0); * * v.lerp(3, 3, 0, 0.5); // v now has components [2,2,0] * *
* *
* * var v1 = createVector(0, 0, 0); * var v2 = createVector(100, 100, 0); * * var v3 = p5.Vector.lerp(v1, v2, 0.5); * // v3 has components [50,50,0] * *
*/ p5.Vector.prototype.lerp = function (x, y, z, amt) { if (x instanceof p5.Vector) { return this.lerp(x.x, x.y, x.z, y); } this.x += (x - this.x) * amt || 0; this.y += (y - this.y) * amt || 0; this.z += (z - this.z) * amt || 0; return this; }; /** * Return a representation of this vector as a float array. This is only * for temporary use. If used in any other fashion, the contents should be * copied by using the p5.Vector.copy() method to copy into your own * array. * * @method array * @return {Number[]} an Array with the 3 values * @example *
* function setup() { * var v = createVector(20,30); * print(v.array()); // Prints : Array [20, 30, 0] * } *
*
* * var v = createVector(10.0, 20.0, 30.0); * var f = v.array(); * print(f[0]); // Prints "10.0" * print(f[1]); // Prints "20.0" * print(f[2]); // Prints "30.0" * *
*/ p5.Vector.prototype.array = function () { return [this.x || 0, this.y || 0, this.z || 0]; }; /** * Equality check against a p5.Vector * * @method equals * @param {Number|p5.Vector|Array} [x] the x component of the vector or a * p5.Vector or an Array * @param {Number} [y] the y component of the vector * @param {Number} [z] the z component of the vector * @return {Boolean} whether the vectors are equals * @example *
* v1 = createVector(5,10,20); * v2 = createVector(5,10,20); * v3 = createVector(13,10,19); * * print(v1.equals(v2.x,v2.y,v2.z)); // true * print(v1.equals(v3.x,v3.y,v3.z)); // false *
*
* * var v1 = createVector(10.0, 20.0, 30.0); * var v2 = createVector(10.0, 20.0, 30.0); * var v3 = createVector(0.0, 0.0, 0.0); * print (v1.equals(v2)) // true * print (v1.equals(v3)) // false * *
*/ p5.Vector.prototype.equals = function (x, y, z) { var a, b, c; if (x instanceof p5.Vector) { a = x.x || 0; b = x.y || 0; c = x.z || 0; } else if (x instanceof Array) { a = x[0] || 0; b = x[1] || 0; c = x[2] || 0; } else { a = x || 0; b = y || 0; c = z || 0; } return this.x === a && this.y === b && this.z === c; }; // Static Methods /** * Make a new 2D unit vector from an angle * * @method fromAngle * @static * @param {Number} angle the desired angle * @return {p5.Vector} the new p5.Vector object * @example *
* * function draw() { * background (200); * * // Create a variable, proportional to the mouseX, * // varying from 0-360, to represent an angle in degrees. * angleMode(DEGREES); * var myDegrees = map(mouseX, 0,width, 0,360); * * // Display that variable in an onscreen text. * // (Note the nfc() function to truncate additional decimal places, * // and the "\xB0" character for the degree symbol.) * var readout = "angle = " + nfc(myDegrees,1,1) + "\xB0" * noStroke(); * fill (0); * text (readout, 5, 15); * * // Create a p5.Vector using the fromAngle function, * // and extract its x and y components. * var v = p5.Vector.fromAngle(radians(myDegrees)); * var vx = v.x; * var vy = v.y; * * push(); * translate (width/2, height/2); * noFill(); * stroke (150); * line (0,0, 30,0); * stroke (0); * line (0,0, 30*vx, 30*vy); * pop() * } * *
*/ p5.Vector.fromAngle = function(angle) { if (this.p5) { if (this.p5._angleMode === constants.DEGREES) { angle = polarGeometry.degreesToRadians(angle); } } if (this.p5) { return new p5.Vector(this.p5,[Math.cos(angle),Math.sin(angle),0]); } else { return new p5.Vector(Math.cos(angle),Math.sin(angle),0); } }; /** * Make a new 2D unit vector from a random angle * * @method random2D * @static * @return {p5.Vector} the new p5.Vector object * @example *
* * var v = p5.Vector.random2D(); * // May make v's attributes something like: * // [0.61554617, -0.51195765, 0.0] or * // [-0.4695841, -0.14366731, 0.0] or * // [0.6091097, -0.22805278, 0.0] * *
*/ p5.Vector.random2D = function () { var angle; // A lot of nonsense to determine if we know about a // p5 sketch and whether we should make a random angle in degrees or radians if (this.p5) { if (this.p5._angleMode === constants.DEGREES) { angle = this.p5.random(360); } else { angle = this.p5.random(constants.TWO_PI); } } else { angle = Math.random()*Math.PI*2; } return this.fromAngle(angle); }; /** * Make a new random 3D unit vector. * * @method random3D * @static * @return {p5.Vector} the new p5.Vector object * @example *
* * var v = p5.Vector.random3D(); * // May make v's attributes something like: * // [0.61554617, -0.51195765, 0.599168] or * // [-0.4695841, -0.14366731, -0.8711202] or * // [0.6091097, -0.22805278, -0.7595902] * *
*/ p5.Vector.random3D = function () { var angle,vz; // If we know about p5 if (this.p5) { angle = this.p5.random(0,constants.TWO_PI); vz = this.p5.random(-1,1); } else { angle = Math.random()*Math.PI*2; vz = Math.random()*2-1; } var vx = Math.sqrt(1-vz*vz)*Math.cos(angle); var vy = Math.sqrt(1-vz*vz)*Math.sin(angle); if (this.p5) { return new p5.Vector(this.p5,[vx,vy,vz]); } else { return new p5.Vector(vx,vy,vz); } }; // Adds two vectors together and returns a new one. /** * @method add * @static * @param {p5.Vector} v1 a p5.Vector to add * @param {p5.Vector} v2 a p5.Vector to add * @param {p5.Vector} target the vector to receive the result */ /** * @method add * @static * @param {p5.Vector} v1 * @param {p5.Vector} v2 * @return {p5.Vector} the resulting p5.Vector * */ p5.Vector.add = function (v1, v2, target) { if (!target) { target = v1.copy(); } else { target.set(v1); } target.add(v2); return target; }; /* * Subtracts one p5.Vector from another and returns a new one. The second * vector (v2) is subtracted from the first (v1), resulting in v1-v2. */ /** * @method sub * @static * @param {p5.Vector} v1 a p5.Vector to subtract from * @param {p5.Vector} v2 a p5.Vector to subtract * @param {p5.Vector} target if undefined a new vector will be created */ /** * @method sub * @static * @param {p5.Vector} v1 * @param {p5.Vector} v2 * @return {p5.Vector} the resulting p5.Vector */ p5.Vector.sub = function (v1, v2, target) { if (!target) { target = v1.copy(); } else { target.set(v1); } target.sub(v2); return target; }; /** * Multiplies a vector by a scalar and returns a new vector. */ /** * @method mult * @static * @param {p5.Vector} v the vector to multiply * @param {Number} n * @param {p5.Vector} target if undefined a new vector will be created */ /** * @method mult * @static * @param {p5.Vector} v * @param {Number} n * @return {p5.Vector} the resulting new p5.Vector */ p5.Vector.mult = function (v, n, target) { if (!target) { target = v.copy(); } else { target.set(v); } target.mult(n); return target; }; /** * Divides a vector by a scalar and returns a new vector. */ /** * @method div * @static * @param {p5.Vector} v the vector to divide * @param {Number} n * @param {p5.Vector} target if undefined a new vector will be created */ /** * @method div * @static * @param {p5.Vector} v * @param {Number} n * @return {p5.Vector} the resulting new p5.Vector */ p5.Vector.div = function (v, n, target) { if (!target) { target = v.copy(); } else { target.set(v); } target.div(n); return target; }; /** * Calculates the dot product of two vectors. */ /** * @method dot * @static * @param {p5.Vector} v1 the first p5.Vector * @param {p5.Vector} v2 the second p5.Vector * @return {Number} the dot product */ p5.Vector.dot = function (v1, v2) { return v1.dot(v2); }; /** * Calculates the cross product of two vectors. */ /** * @method cross * @static * @param {p5.Vector} v1 the first p5.Vector * @param {p5.Vector} v2 the second p5.Vector * @return {Number} the cross product */ p5.Vector.cross = function (v1, v2) { return v1.cross(v2); }; /** * Calculates the Euclidean distance between two points (considering a * point as a vector object). */ /** * @method dist * @static * @param {p5.Vector} v1 the first p5.Vector * @param {p5.Vector} v2 the second p5.Vector * @return {Number} the distance */ p5.Vector.dist = function (v1,v2) { return v1.dist(v2); }; /** * Linear interpolate a vector to another vector and return the result as a * new vector. */ /** * @method lerp * @static * @param {p5.Vector} v1 * @param {p5.Vector} v2 * @param {Number} amt * @param {p5.Vector} target if undefined a new vector will be created */ /** * @method lerp * @static * @param {p5.Vector} v1 * @param {p5.Vector} v2 * @param {Number} amt * @return {Number} the lerped value */ p5.Vector.lerp = function (v1, v2, amt, target) { if (!target) { target = v1.copy(); } else { target.set(v1); } target.lerp(v2, amt); return target; }; /** * @method mag * @param {p5.Vector} vecT the vector to return the magnitude of * @return {Number} the magnitude of vecT * @static */ p5.Vector.mag = function (vecT){ var x = vecT.x, y = vecT.y, z = vecT.z; var magSq = x * x + y * y + z * z; return Math.sqrt(magSq); }; module.exports = p5.Vector; },{"../core/constants":4,"../core/core":5,"./polargeometry":24}],24:[function(_dereq_,module,exports){ module.exports = { degreesToRadians: function(x) { return 2 * Math.PI * x / 360; }, radiansToDegrees: function(x) { return 360 * x / (2 * Math.PI); } }; },{}],25:[function(_dereq_,module,exports){ /** * @module Math * @submodule Random * @for p5 * @requires core */ 'use strict'; var p5 = _dereq_('../core/core'); var seeded = false; var previous = false; var y2 = 0; // Linear Congruential Generator // Variant of a Lehman Generator var lcg = (function() { // Set to values from http://en.wikipedia.org/wiki/Numerical_Recipes // m is basically chosen to be large (as it is the max period) // and for its relationships to a and c var m = 4294967296, // a - 1 should be divisible by m's prime factors a = 1664525, // c and m should be co-prime c = 1013904223, seed, z; return { setSeed : function(val) { // pick a random seed if val is undefined or null // the >>> 0 casts the seed to an unsigned 32-bit integer z = seed = (val == null ? Math.random() * m : val) >>> 0; }, getSeed : function() { return seed; }, rand : function() { // define the recurrence relationship z = (a * z + c) % m; // return a float in [0, 1) // if z = m then z / m = 0 therefore (z % m) / m < 1 always return z / m; } }; }()); /** * Sets the seed value for random(). * * By default, random() produces different results each time the program * is run. Set the seed parameter to a constant to return the same * pseudo-random numbers each time the software is run. * * @method randomSeed * @param {Number} seed the seed value * @example *
* * randomSeed(99); * for (var i=0; i < 100; i++) { * var r = random(0, 255); * stroke(r); * line(i, 0, i, 100); * } * *
* * @alt * many vertical lines drawn in white, black or grey. * */ p5.prototype.randomSeed = function(seed) { lcg.setSeed(seed); seeded = true; previous = false; }; /** * Return a random floating-point number. * * Takes either 0, 1 or 2 arguments. * * If no argument is given, returns a random number from 0 * up to (but not including) 1. * * If one argument is given and it is a number, returns a random number from 0 * up to (but not including) the number. * * If one argument is given and it is an array, returns a random element from * that array. * * If two arguments are given, returns a random number from the * first argument up to (but not including) the second argument. * * @method random * @param {Number} [min] the lower bound (inclusive) * @param {Number} [max] the upper bound (exclusive) * @return {Number} the random number * @example *
* * for (var i = 0; i < 100; i++) { * var r = random(50); * stroke(r*5); * line(50, i, 50+r, i); * } * *
*
* * for (var i = 0; i < 100; i++) { * var r = random(-50, 50); * line(50,i,50+r,i); * } * *
*
* * // Get a random element from an array using the random(Array) syntax * var words = [ "apple", "bear", "cat", "dog" ]; * var word = random(words); // select random word * text(word,10,50); // draw the word * *
* * @alt * 100 horizontal lines from center canvas to right. size+fill change each time * 100 horizontal lines from center of canvas. height & side change each render * word displayed at random. Either apple, bear, cat, or dog * */ /** * @method random * @param {Array} choices the array to choose from * @return {*} the random element from the array * @example */ p5.prototype.random = function (min, max) { var rand; if (seeded) { rand = lcg.rand(); } else { rand = Math.random(); } if (typeof min === 'undefined') { return rand; } else if (typeof max === 'undefined') { if (min instanceof Array) { return min[Math.floor(rand * min.length)]; } else { return rand * min; } } else { if (min > max) { var tmp = min; min = max; max = tmp; } return rand * (max-min) + min; } }; /** * * Returns a random number fitting a Gaussian, or * normal, distribution. There is theoretically no minimum or maximum * value that randomGaussian() might return. Rather, there is * just a very low probability that values far from the mean will be * returned; and a higher probability that numbers near the mean will * be returned. *

* Takes either 0, 1 or 2 arguments.
* If no args, returns a mean of 0 and standard deviation of 1.
* If one arg, that arg is the mean (standard deviation is 1).
* If two args, first is mean, second is standard deviation. * * @method randomGaussian * @param {Number} mean the mean * @param {Number} sd the standard deviation * @return {Number} the random number * @example *
* for (var y = 0; y < 100; y++) { * var x = randomGaussian(50,15); * line(50, y, x, y); *} * *
*
* *var distribution = new Array(360); * *function setup() { * createCanvas(100, 100); * for (var i = 0; i < distribution.length; i++) { * distribution[i] = floor(randomGaussian(0,15)); * } *} * *function draw() { * background(204); * * translate(width/2, width/2); * * for (var i = 0; i < distribution.length; i++) { * rotate(TWO_PI/distribution.length); * stroke(0); * var dist = abs(distribution[i]); * line(0, 0, dist, 0); * } *} * *
* @alt * 100 horizontal lines from center of canvas. height & side change each render * black lines radiate from center of canvas. size determined each render */ p5.prototype.randomGaussian = function(mean, sd) { var y1,x1,x2,w; if (previous) { y1 = y2; previous = false; } else { do { x1 = this.random(2) - 1; x2 = this.random(2) - 1; w = x1 * x1 + x2 * x2; } while (w >= 1); w = Math.sqrt((-2 * Math.log(w))/w); y1 = x1 * w; y2 = x2 * w; previous = true; } var m = mean || 0; var s = sd || 1; return y1*s + m; }; module.exports = p5; },{"../core/core":5}],26:[function(_dereq_,module,exports){ /** * @module Math * @submodule Trigonometry * @for p5 * @requires core * @requires polargeometry * @requires constants */ 'use strict'; var p5 = _dereq_('../core/core'); var polarGeometry = _dereq_('./polargeometry'); var constants = _dereq_('../core/constants'); p5.prototype._angleMode = constants.RADIANS; /** * The inverse of cos(), returns the arc cosine of a value. This function * expects the values in the range of -1 to 1 and values are returned in * the range 0 to PI (3.1415927). * * @method acos * @param {Number} value the value whose arc cosine is to be returned * @return {Number} the arc cosine of the given value * * @example *
* * var a = PI; * var c = cos(a); * var ac = acos(c); * // Prints: "3.1415927 : -1.0 : 3.1415927" * print(a + " : " + c + " : " + ac); * *
* *
* * var a = PI + PI/4.0; * var c = cos(a); * var ac = acos(c); * // Prints: "3.926991 : -0.70710665 : 2.3561943" * print(a + " : " + c + " : " + ac); * *
*/ p5.prototype.acos = function(ratio) { if (this._angleMode === constants.RADIANS) { return Math.acos(ratio); } else { return polarGeometry.radiansToDegrees(Math.acos(ratio)); } }; /** * The inverse of sin(), returns the arc sine of a value. This function * expects the values in the range of -1 to 1 and values are returned * in the range -PI/2 to PI/2. * * @method asin * @param {Number} value the value whose arc sine is to be returned * @return {Number} the arc sine of the given value * * @example *
* * var a = PI + PI/3; * var s = sin(a); * var as = asin(s); * // Prints: "1.0471976 : 0.86602545 : 1.0471976" * print(a + " : " + s + " : " + as); * *
* *
* * var a = PI + PI/3.0; * var s = sin(a); * var as = asin(s); * // Prints: "4.1887903 : -0.86602545 : -1.0471976" * print(a + " : " + s + " : " + as); * *
* */ p5.prototype.asin = function(ratio) { if (this._angleMode === constants.RADIANS) { return Math.asin(ratio); } else { return polarGeometry.radiansToDegrees(Math.asin(ratio)); } }; /** * The inverse of tan(), returns the arc tangent of a value. This function * expects the values in the range of -Infinity to Infinity (exclusive) and * values are returned in the range -PI/2 to PI/2. * * @method atan * @param {Number} value the value whose arc tangent is to be returned * @return {Number} the arc tangent of the given value * * @example *
* * var a = PI + PI/3; * var t = tan(a); * var at = atan(t); * // Prints: "1.0471976 : 1.7320509 : 1.0471976" * print(a + " : " + t + " : " + at); * *
* *
* * var a = PI + PI/3.0; * var t = tan(a); * var at = atan(t); * // Prints: "4.1887903 : 1.7320513 : 1.0471977" * print(a + " : " + t + " : " + at); * *
* */ p5.prototype.atan = function(ratio) { if (this._angleMode === constants.RADIANS) { return Math.atan(ratio); } else { return polarGeometry.radiansToDegrees(Math.atan(ratio)); } }; /** * Calculates the angle (in radians) from a specified point to the coordinate * origin as measured from the positive x-axis. Values are returned as a * float in the range from PI to -PI. The atan2() function is most often used * for orienting geometry to the position of the cursor. *

* Note: The y-coordinate of the point is the first parameter, and the * x-coordinate is the second parameter, due the the structure of calculating * the tangent. * * @method atan2 * @param {Number} y y-coordinate of the point * @param {Number} x x-coordinate of the point * @return {Number} the arc tangent of the given point * * @example *
* * function draw() { * background(204); * translate(width/2, height/2); * var a = atan2(mouseY-height/2, mouseX-width/2); * rotate(a); * rect(-30, -5, 60, 10); * } * *
* * @alt * 60 by 10 rect at center of canvas rotates with mouse movements * */ p5.prototype.atan2 = function (y, x) { if (this._angleMode === constants.RADIANS) { return Math.atan2(y, x); } else { return polarGeometry.radiansToDegrees(Math.atan2(y, x)); } }; /** * Calculates the cosine of an angle. This function takes into account the * current angleMode. Values are returned in the range -1 to 1. * * @method cos * @param {Number} angle the angle * @return {Number} the cosine of the angle * * @example *
* * var a = 0.0; * var inc = TWO_PI/25.0; * for (var i = 0; i < 25; i++) { * line(i*4, 50, i*4, 50+cos(a)*40.0); * a = a + inc; * } * *
* * @alt * vertical black lines form wave patterns, extend-down on left and right side * */ p5.prototype.cos = function(angle) { if (this._angleMode === constants.RADIANS) { return Math.cos(angle); } else { return Math.cos(this.radians(angle)); } }; /** * Calculates the sine of an angle. This function takes into account the * current angleMode. Values are returned in the range -1 to 1. * * @method sin * @param {Number} angle the angle * @return {Number} the sine of the angle * * @example *
* * var a = 0.0; * var inc = TWO_PI/25.0; * for (var i = 0; i < 25; i++) { * line(i*4, 50, i*4, 50+sin(a)*40.0); * a = a + inc; * } * *
* * @alt * vertical black lines extend down and up from center to form wave pattern * */ p5.prototype.sin = function(angle) { if (this._angleMode === constants.RADIANS) { return Math.sin(angle); } else { return Math.sin(this.radians(angle)); } }; /** * Calculates the tangent of an angle. This function takes into account * the current angleMode. Values are returned in the range -1 to 1. * * @method tan * @param {Number} angle the angle * @return {Number} the tangent of the angle * * @example *
* * var a = 0.0; * var inc = TWO_PI/50.0; * for (var i = 0; i < 100; i = i+2) { * line(i, 50, i, 50+tan(a)*2.0); * a = a + inc; * } * * * * @alt * vertical black lines end down and up from center to form spike pattern * */ p5.prototype.tan = function(angle) { if (this._angleMode === constants.RADIANS) { return Math.tan(angle); } else { return Math.tan(this.radians(angle)); } }; /** * Converts a radian measurement to its corresponding value in degrees. * Radians and degrees are two ways of measuring the same thing. There are * 360 degrees in a circle and 2*PI radians in a circle. For example, * 90° = PI/2 = 1.5707964. * * @method degrees * @param {Number} radians the radians value to convert to degrees * @return {Number} the converted angle * * * @example *
* * var rad = PI/4; * var deg = degrees(rad); * print(rad + " radians is " + deg + " degrees"); * // Prints: 0.7853981633974483 radians is 45 degrees * *
* */ p5.prototype.degrees = function(angle) { return polarGeometry.radiansToDegrees(angle); }; /** * Converts a degree measurement to its corresponding value in radians. * Radians and degrees are two ways of measuring the same thing. There are * 360 degrees in a circle and 2*PI radians in a circle. For example, * 90° = PI/2 = 1.5707964. * * @method radians * @param {Number} degrees the degree value to convert to radians * @return {Number} the converted angle * * @example *
* * var deg = 45.0; * var rad = radians(deg); * print(deg + " degrees is " + rad + " radians"); * // Prints: 45 degrees is 0.7853981633974483 radians * *
*/ p5.prototype.radians = function(angle) { return polarGeometry.degreesToRadians(angle); }; /** * Sets the current mode of p5 to given mode. Default mode is RADIANS. * * @method angleMode * @param {Constant} mode either RADIANS or DEGREES * * @example *
* * function draw(){ * background(204); * angleMode(DEGREES); // Change the mode to DEGREES * var a = atan2(mouseY-height/2, mouseX-width/2); * translate(width/2, height/2); * push(); * rotate(a); * rect(-20, -5, 40, 10); // Larger rectangle is rotating in degrees * pop(); * angleMode(RADIANS); // Change the mode to RADIANS * rotate(a); // var a stays the same * rect(-40, -5, 20, 10); // Smaller rectangle is rotating in radians * } * *
* * @alt * 40 by 10 rect in center rotates with mouse moves. 20 by 10 rect moves faster. * * */ p5.prototype.angleMode = function(mode) { if (mode === constants.DEGREES || mode === constants.RADIANS) { this._angleMode = mode; } }; module.exports = p5; },{"../core/constants":4,"../core/core":5,"./polargeometry":24}],27:[function(_dereq_,module,exports){ /** * @requires constants * @todo see methods below needing further implementation. * future consideration: implement SIMD optimizations * when browser compatibility becomes available * https://developer.mozilla.org/en-US/docs/Web/JavaScript/ * Reference/Global_Objects/SIMD */ 'use strict'; var p5 = _dereq_('../core/core'); var polarGeometry = _dereq_('../math/polargeometry'); var constants = _dereq_('../core/constants'); var GLMAT_ARRAY_TYPE = ( typeof Float32Array !== 'undefined') ? Float32Array : Array; /** * A class to describe a 4x4 matrix * for model and view matrix manipulation in the p5js webgl renderer. * class p5.Matrix * @constructor * @param {Array} [mat4] array literal of our 4x4 matrix */ p5.Matrix = function() { var args = new Array(arguments.length); for (var i = 0; i < args.length; ++i) { args[i] = arguments[i]; } // This is default behavior when object // instantiated using createMatrix() // @todo implement createMatrix() in core/math.js if(args[0] instanceof p5) { // save reference to p5 if passed in this.p5 = args[0]; if(args[1] === 'mat3'){ this.mat3 = args[2] || new GLMAT_ARRAY_TYPE([ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]); } else { this.mat4 = args[1] || new GLMAT_ARRAY_TYPE([ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ]); } // default behavior when object // instantiated using new p5.Matrix() } else { if(args[0] === 'mat3'){ this.mat3 = args[1] || new GLMAT_ARRAY_TYPE([ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]); } else { this.mat4 = args[0] || new GLMAT_ARRAY_TYPE([ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ]); } } return this; }; /** * Sets the x, y, and z component of the vector using two or three separate * variables, the data from a p5.Matrix, or the values from a float array. * * @param {p5.Matrix|Float32Array|Array} [inMatrix] the input p5.Matrix or * an Array of length 16 * @chainable */ p5.Matrix.prototype.set = function (inMatrix) { if (inMatrix instanceof p5.Matrix) { this.mat4 = inMatrix.mat4; return this; } else if (inMatrix instanceof GLMAT_ARRAY_TYPE) { this.mat4 = inMatrix; return this; } return this; }; /** * Gets a copy of the vector, returns a p5.Matrix object. * * @return {p5.Matrix} the copy of the p5.Matrix object */ p5.Matrix.prototype.get = function () { return new p5.Matrix(this.mat4); }; /** * return a copy of a matrix * @return {p5.Matrix} the result matrix */ p5.Matrix.prototype.copy = function(){ var copied = new p5.Matrix(); copied.mat4[0] = this.mat4[0]; copied.mat4[1] = this.mat4[1]; copied.mat4[2] = this.mat4[2]; copied.mat4[3] = this.mat4[3]; copied.mat4[4] = this.mat4[4]; copied.mat4[5] = this.mat4[5]; copied.mat4[6] = this.mat4[6]; copied.mat4[7] = this.mat4[7]; copied.mat4[8] = this.mat4[8]; copied.mat4[9] = this.mat4[9]; copied.mat4[10] = this.mat4[10]; copied.mat4[11] = this.mat4[11]; copied.mat4[12] = this.mat4[12]; copied.mat4[13] = this.mat4[13]; copied.mat4[14] = this.mat4[14]; copied.mat4[15] = this.mat4[15]; return copied; }; /** * return an identity matrix * @return {p5.Matrix} the result matrix */ p5.Matrix.identity = function(){ return new p5.Matrix(); }; /** * transpose according to a given matrix * @param {p5.Matrix|Float32Array|Array} a the matrix to be based on to transpose * @chainable */ p5.Matrix.prototype.transpose = function(a){ var a01, a02, a03, a12, a13, a23; if(a instanceof p5.Matrix){ a01 = a.mat4[1]; a02 = a.mat4[2]; a03 = a.mat4[3]; a12 = a.mat4[6]; a13 = a.mat4[7]; a23 = a.mat4[11]; this.mat4[0] = a.mat4[0]; this.mat4[1] = a.mat4[4]; this.mat4[2] = a.mat4[8]; this.mat4[3] = a.mat4[12]; this.mat4[4] = a01; this.mat4[5] = a.mat4[5]; this.mat4[6] = a.mat4[9]; this.mat4[7] = a.mat4[13]; this.mat4[8] = a02; this.mat4[9] = a12; this.mat4[10] = a.mat4[10]; this.mat4[11] = a.mat4[14]; this.mat4[12] = a03; this.mat4[13] = a13; this.mat4[14] = a23; this.mat4[15] = a.mat4[15]; }else if(a instanceof GLMAT_ARRAY_TYPE){ a01 = a[1]; a02 = a[2]; a03 = a[3]; a12 = a[6]; a13 = a[7]; a23 = a[11]; this.mat4[0] = a[0]; this.mat4[1] = a[4]; this.mat4[2] = a[8]; this.mat4[3] = a[12]; this.mat4[4] = a01; this.mat4[5] = a[5]; this.mat4[6] = a[9]; this.mat4[7] = a[13]; this.mat4[8] = a02; this.mat4[9] = a12; this.mat4[10] = a[10]; this.mat4[11] = a[14]; this.mat4[12] = a03; this.mat4[13] = a13; this.mat4[14] = a23; this.mat4[15] = a[15]; } return this; }; /** * invert matrix according to a give matrix * @param {p5.Matrix|Float32Array|Array} a the matrix to be based on to invert * @chainable */ p5.Matrix.prototype.invert = function(a){ var a00, a01, a02, a03, a10, a11, a12, a13, a20, a21, a22, a23, a30, a31, a32, a33; if(a instanceof p5.Matrix){ a00 = a.mat4[0]; a01 = a.mat4[1]; a02 = a.mat4[2]; a03 = a.mat4[3]; a10 = a.mat4[4]; a11 = a.mat4[5]; a12 = a.mat4[6]; a13 = a.mat4[7]; a20 = a.mat4[8]; a21 = a.mat4[9]; a22 = a.mat4[10]; a23 = a.mat4[11]; a30 = a.mat4[12]; a31 = a.mat4[13]; a32 = a.mat4[14]; a33 = a.mat4[15]; }else if(a instanceof GLMAT_ARRAY_TYPE){ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; a30 = a[12]; a31 = a[13]; a32 = a[14]; a33 = a[15]; } var b00 = a00 * a11 - a01 * a10, b01 = a00 * a12 - a02 * a10, b02 = a00 * a13 - a03 * a10, b03 = a01 * a12 - a02 * a11, b04 = a01 * a13 - a03 * a11, b05 = a02 * a13 - a03 * a12, b06 = a20 * a31 - a21 * a30, b07 = a20 * a32 - a22 * a30, b08 = a20 * a33 - a23 * a30, b09 = a21 * a32 - a22 * a31, b10 = a21 * a33 - a23 * a31, b11 = a22 * a33 - a23 * a32, // Calculate the determinant det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; if (!det) { return null; } det = 1.0 / det; this.mat4[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; this.mat4[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; this.mat4[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; this.mat4[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; this.mat4[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; this.mat4[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; this.mat4[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; this.mat4[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; this.mat4[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; this.mat4[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; this.mat4[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; this.mat4[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; this.mat4[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; this.mat4[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; this.mat4[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; this.mat4[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; return this; }; /** * Inverts a 3x3 matrix * @chainable */ p5.Matrix.prototype.invert3x3 = function (){ var a00 = this.mat3[0], a01 = this.mat3[1], a02 = this.mat3[2], a10 = this.mat3[3], a11 = this.mat3[4], a12 = this.mat3[5], a20 = this.mat3[6], a21 = this.mat3[7], a22 = this.mat3[8], b01 = a22 * a11 - a12 * a21, b11 = -a22 * a10 + a12 * a20, b21 = a21 * a10 - a11 * a20, // Calculate the determinant det = a00 * b01 + a01 * b11 + a02 * b21; if (!det) { return null; } det = 1.0 / det; this.mat3[0] = b01 * det; this.mat3[1] = (-a22 * a01 + a02 * a21) * det; this.mat3[2] = (a12 * a01 - a02 * a11) * det; this.mat3[3] = b11 * det; this.mat3[4] = (a22 * a00 - a02 * a20) * det; this.mat3[5] = (-a12 * a00 + a02 * a10) * det; this.mat3[6] = b21 * det; this.mat3[7] = (-a21 * a00 + a01 * a20) * det; this.mat3[8] = (a11 * a00 - a01 * a10) * det; return this; }; /** * transposes a 3x3 p5.Matrix by a mat3 * @param {[Number]} mat3 1-dimensional array * @chainable */ p5.Matrix.prototype.transpose3x3 = function (mat3){ var a01 = mat3[1], a02 = mat3[2], a12 = mat3[5]; this.mat3[1] = mat3[3]; this.mat3[2] = mat3[6]; this.mat3[3] = a01; this.mat3[5] = mat3[7]; this.mat3[6] = a02; this.mat3[7] = a12; return this; }; /** * converts a 4x4 matrix to its 3x3 inverse tranform * commonly used in MVMatrix to NMatrix conversions. * @param {p5.Matrix} mat4 the matrix to be based on to invert * @chainable * @todo finish implementation */ p5.Matrix.prototype.inverseTranspose = function (matrix){ if(this.mat3 === undefined){ console.error('sorry, this function only works with mat3'); } else { //convert mat4 -> mat3 this.mat3[0] = matrix.mat4[0]; this.mat3[1] = matrix.mat4[1]; this.mat3[2] = matrix.mat4[2]; this.mat3[3] = matrix.mat4[4]; this.mat3[4] = matrix.mat4[5]; this.mat3[5] = matrix.mat4[6]; this.mat3[6] = matrix.mat4[8]; this.mat3[7] = matrix.mat4[9]; this.mat3[8] = matrix.mat4[10]; } this.invert3x3().transpose3x3(this.mat3); return this; }; /** * inspired by Toji's mat4 determinant * @return {Number} Determinant of our 4x4 matrix */ p5.Matrix.prototype.determinant = function(){ var d00 = (this.mat4[0] * this.mat4[5]) - (this.mat4[1] * this.mat4[4]), d01 = (this.mat4[0] * this.mat4[6]) - (this.mat4[2] * this.mat4[4]), d02 = (this.mat4[0] * this.mat4[7]) - (this.mat4[3] * this.mat4[4]), d03 = (this.mat4[1] * this.mat4[6]) - (this.mat4[2] * this.mat4[5]), d04 = (this.mat4[1] * this.mat4[7]) - (this.mat4[3] * this.mat4[5]), d05 = (this.mat4[2] * this.mat4[7]) - (this.mat4[3] * this.mat4[6]), d06 = (this.mat4[8] * this.mat4[13]) - (this.mat4[9] * this.mat4[12]), d07 = (this.mat4[8] * this.mat4[14]) - (this.mat4[10] * this.mat4[12]), d08 = (this.mat4[8] * this.mat4[15]) - (this.mat4[11] * this.mat4[12]), d09 = (this.mat4[9] * this.mat4[14]) - (this.mat4[10] * this.mat4[13]), d10 = (this.mat4[9] * this.mat4[15]) - (this.mat4[11] * this.mat4[13]), d11 = (this.mat4[10] * this.mat4[15]) - (this.mat4[11] * this.mat4[14]); // Calculate the determinant return d00 * d11 - d01 * d10 + d02 * d09 + d03 * d08 - d04 * d07 + d05 * d06; }; /** * multiply two mat4s * @param {p5.Matrix|Float32Array|Array} multMatrix The matrix * we want to multiply by * @chainable */ p5.Matrix.prototype.mult = function(multMatrix){ var _dest = new GLMAT_ARRAY_TYPE(16); var _src = new GLMAT_ARRAY_TYPE(16); if(multMatrix instanceof p5.Matrix) { _src = multMatrix.mat4; } else if(multMatrix instanceof GLMAT_ARRAY_TYPE){ _src = multMatrix; } // each row is used for the multiplier var b0 = this.mat4[0], b1 = this.mat4[1], b2 = this.mat4[2], b3 = this.mat4[3]; _dest[0] = b0*_src[0] + b1*_src[4] + b2*_src[8] + b3*_src[12]; _dest[1] = b0*_src[1] + b1*_src[5] + b2*_src[9] + b3*_src[13]; _dest[2] = b0*_src[2] + b1*_src[6] + b2*_src[10] + b3*_src[14]; _dest[3] = b0*_src[3] + b1*_src[7] + b2*_src[11] + b3*_src[15]; b0 = this.mat4[4]; b1 = this.mat4[5]; b2 = this.mat4[6]; b3 = this.mat4[7]; _dest[4] = b0*_src[0] + b1*_src[4] + b2*_src[8] + b3*_src[12]; _dest[5] = b0*_src[1] + b1*_src[5] + b2*_src[9] + b3*_src[13]; _dest[6] = b0*_src[2] + b1*_src[6] + b2*_src[10] + b3*_src[14]; _dest[7] = b0*_src[3] + b1*_src[7] + b2*_src[11] + b3*_src[15]; b0 = this.mat4[8]; b1 = this.mat4[9]; b2 = this.mat4[10]; b3 = this.mat4[11]; _dest[8] = b0*_src[0] + b1*_src[4] + b2*_src[8] + b3*_src[12]; _dest[9] = b0*_src[1] + b1*_src[5] + b2*_src[9] + b3*_src[13]; _dest[10] = b0*_src[2] + b1*_src[6] + b2*_src[10] + b3*_src[14]; _dest[11] = b0*_src[3] + b1*_src[7] + b2*_src[11] + b3*_src[15]; b0 = this.mat4[12]; b1 = this.mat4[13]; b2 = this.mat4[14]; b3 = this.mat4[15]; _dest[12] = b0*_src[0] + b1*_src[4] + b2*_src[8] + b3*_src[12]; _dest[13] = b0*_src[1] + b1*_src[5] + b2*_src[9] + b3*_src[13]; _dest[14] = b0*_src[2] + b1*_src[6] + b2*_src[10] + b3*_src[14]; _dest[15] = b0*_src[3] + b1*_src[7] + b2*_src[11] + b3*_src[15]; this.mat4 = _dest; return this; }; /** * scales a p5.Matrix by scalars or a vector * @param {p5.Vector|Float32Array|Array} s vector to scale by * @chainable */ p5.Matrix.prototype.scale = function() { var x,y,z; var args = new Array(arguments.length); for (var i = 0; i < args.length; ++i) { args[i] = arguments[i]; } //if our 1st arg is a type p5.Vector if (args[0] instanceof p5.Vector){ x = args[0].x; y = args[0].y; z = args[0].z; } //otherwise if it's an array else if (args[0] instanceof Array){ x = args[0][0]; y = args[0][1]; z = args[0][2]; } var _dest = new GLMAT_ARRAY_TYPE(16); _dest[0] = this.mat4[0] * x; _dest[1] = this.mat4[1] * x; _dest[2] = this.mat4[2] * x; _dest[3] = this.mat4[3] * x; _dest[4] = this.mat4[4] * y; _dest[5] = this.mat4[5] * y; _dest[6] = this.mat4[6] * y; _dest[7] = this.mat4[7] * y; _dest[8] = this.mat4[8] * z; _dest[9] = this.mat4[9] * z; _dest[10] = this.mat4[10] * z; _dest[11] = this.mat4[11] * z; _dest[12] = this.mat4[12]; _dest[13] = this.mat4[13]; _dest[14] = this.mat4[14]; _dest[15] = this.mat4[15]; this.mat4 = _dest; return this; }; /** * rotate our Matrix around an axis by the given angle. * @param {Number} a The angle of rotation in radians * @param {p5.Vector|Array} axis the axis(es) to rotate around * @chainable * inspired by Toji's gl-matrix lib, mat4 rotation */ p5.Matrix.prototype.rotate = function(a, axis){ var x, y, z, _a, len; if (this.p5) { if (this.p5._angleMode === constants.DEGREES) { _a = polarGeometry.degreesToRadians(a); } } else { _a = a; } if (axis instanceof p5.Vector) { x = axis.x; y = axis.y; z = axis.z; } else if (axis instanceof Array) { x = axis[0]; y = axis[1]; z = axis[2]; } len = Math.sqrt(x * x + y * y + z * z); x *= (1/len); y *= (1/len); z *= (1/len); var a00 = this.mat4[0]; var a01 = this.mat4[1]; var a02 = this.mat4[2]; var a03 = this.mat4[3]; var a10 = this.mat4[4]; var a11 = this.mat4[5]; var a12 = this.mat4[6]; var a13 = this.mat4[7]; var a20 = this.mat4[8]; var a21 = this.mat4[9]; var a22 = this.mat4[10]; var a23 = this.mat4[11]; //sin,cos, and tan of respective angle var sA = Math.sin(_a); var cA = Math.cos(_a); var tA = 1 - cA; // Construct the elements of the rotation matrix var b00 = x * x * tA + cA; var b01 = y * x * tA + z * sA; var b02 = z * x * tA - y * sA; var b10 = x * y * tA - z * sA; var b11 = y * y * tA + cA; var b12 = z * y * tA + x * sA; var b20 = x * z * tA + y * sA; var b21 = y * z * tA - x * sA; var b22 = z * z * tA + cA; // rotation-specific matrix multiplication this.mat4[0] = a00 * b00 + a10 * b01 + a20 * b02; this.mat4[1] = a01 * b00 + a11 * b01 + a21 * b02; this.mat4[2] = a02 * b00 + a12 * b01 + a22 * b02; this.mat4[3] = a03 * b00 + a13 * b01 + a23 * b02; this.mat4[4] = a00 * b10 + a10 * b11 + a20 * b12; this.mat4[5] = a01 * b10 + a11 * b11 + a21 * b12; this.mat4[6] = a02 * b10 + a12 * b11 + a22 * b12; this.mat4[7] = a03 * b10 + a13 * b11 + a23 * b12; this.mat4[8] = a00 * b20 + a10 * b21 + a20 * b22; this.mat4[9] = a01 * b20 + a11 * b21 + a21 * b22; this.mat4[10] = a02 * b20 + a12 * b21 + a22 * b22; this.mat4[11] = a03 * b20 + a13 * b21 + a23 * b22; return this; }; /** * @todo finish implementing this method! * translates * @param {Number[]} v vector to translate by * @chainable */ p5.Matrix.prototype.translate = function(v){ var x = v[0], y = v[1], z = v[2] || 0; this.mat4[12] = this.mat4[0] * x +this.mat4[4] * y +this.mat4[8] * z +this.mat4[12]; this.mat4[13] = this.mat4[1] * x +this.mat4[5] * y +this.mat4[9] * z +this.mat4[13]; this.mat4[14] = this.mat4[2] * x +this.mat4[6] * y +this.mat4[10] * z +this.mat4[14]; this.mat4[15] = this.mat4[3] * x +this.mat4[7] * y +this.mat4[11] * z +this.mat4[15]; }; p5.Matrix.prototype.rotateX = function(a){ this.rotate(a, [1,0,0]); }; p5.Matrix.prototype.rotateY = function(a){ this.rotate(a, [0,1,0]); }; p5.Matrix.prototype.rotateZ = function(a){ this.rotate(a, [0,0,1]); }; /** * sets the perspective matrix * @param {Number} fovy [description] * @param {Number} aspect [description] * @param {Number} near near clipping plane * @param {Number} far far clipping plane * @chainable */ p5.Matrix.prototype.perspective = function(fovy,aspect,near,far){ var f = 1.0 / Math.tan(fovy / 2), nf = 1 / (near - far); this.mat4[0] = f / aspect; this.mat4[1] = 0; this.mat4[2] = 0; this.mat4[3] = 0; this.mat4[4] = 0; this.mat4[5] = f; this.mat4[6] = 0; this.mat4[7] = 0; this.mat4[8] = 0; this.mat4[9] = 0; this.mat4[10] = (far + near) * nf; this.mat4[11] = -1; this.mat4[12] = 0; this.mat4[13] = 0; this.mat4[14] = (2 * far * near) * nf; this.mat4[15] = 0; return this; }; /** * sets the ortho matrix * @param {Number} left [description] * @param {Number} right [description] * @param {Number} bottom [description] * @param {Number} top [description] * @param {Number} near near clipping plane * @param {Number} far far clipping plane * @chainable */ p5.Matrix.prototype.ortho = function(left,right,bottom,top,near,far){ var lr = 1 / (left - right), bt = 1 / (bottom - top), nf = 1 / (near - far); this.mat4[0] = -2 * lr; this.mat4[1] = 0; this.mat4[2] = 0; this.mat4[3] = 0; this.mat4[4] = 0; this.mat4[5] = -2 * bt; this.mat4[6] = 0; this.mat4[7] = 0; this.mat4[8] = 0; this.mat4[9] = 0; this.mat4[10] = 2 * nf; this.mat4[11] = 0; this.mat4[12] = (left + right) * lr; this.mat4[13] = (top + bottom) * bt; this.mat4[14] = (far + near) * nf; this.mat4[15] = 1; return this; }; /** * PRIVATE */ // matrix methods adapted from: // https://developer.mozilla.org/en-US/docs/Web/WebGL/ // gluPerspective // // function _makePerspective(fovy, aspect, znear, zfar){ // var ymax = znear * Math.tan(fovy * Math.PI / 360.0); // var ymin = -ymax; // var xmin = ymin * aspect; // var xmax = ymax * aspect; // return _makeFrustum(xmin, xmax, ymin, ymax, znear, zfar); // } //// //// glFrustum //// //function _makeFrustum(left, right, bottom, top, znear, zfar){ // var X = 2*znear/(right-left); // var Y = 2*znear/(top-bottom); // var A = (right+left)/(right-left); // var B = (top+bottom)/(top-bottom); // var C = -(zfar+znear)/(zfar-znear); // var D = -2*zfar*znear/(zfar-znear); // var frustrumMatrix =[ // X, 0, A, 0, // 0, Y, B, 0, // 0, 0, C, D, // 0, 0, -1, 0 //]; //return frustrumMatrix; // } // function _setMVPMatrices(){ ////an identity matrix ////@TODO use the p5.Matrix class to abstract away our MV matrices and ///other math //var _mvMatrix = //[ // 1.0,0.0,0.0,0.0, // 0.0,1.0,0.0,0.0, // 0.0,0.0,1.0,0.0, // 0.0,0.0,0.0,1.0 //]; module.exports = p5.Matrix; },{"../core/constants":4,"../core/core":5,"../math/polargeometry":24}],28:[function(_dereq_,module,exports){ 'use strict'; var p5 = _dereq_('../core/core'); var shader = _dereq_('./shader'); _dereq_('../core/p5.Renderer'); _dereq_('./p5.Matrix'); var uMVMatrixStack = []; //@TODO should implement public method //to override these attributes var attributes = { alpha: true, depth: true, stencil: true, antialias: false, premultipliedAlpha: false, preserveDrawingBuffer: false }; /** * 3D graphics class * @class p5.RendererGL * @constructor * @extends p5.Renderer * @todo extend class to include public method for offscreen * rendering (FBO). * */ p5.RendererGL = function(elt, pInst, isMainCanvas) { p5.Renderer.call(this, elt, pInst, isMainCanvas); this._initContext(); this.isP3D = true; //lets us know we're in 3d mode this.GL = this.drawingContext; //lights this.ambientLightCount = 0; this.directionalLightCount = 0; this.pointLightCount = 0; //camera this._curCamera = null; /** * model view, projection, & normal * matrices */ this.uMVMatrix = new p5.Matrix(); this.uPMatrix = new p5.Matrix(); this.uNMatrix = new p5.Matrix('mat3'); //Geometry & Material hashes this.gHash = {}; this.mHash = {}; //Imediate Mode //default drawing is done in Retained Mode this.isImmediateDrawing = false; this.immediateMode = {}; this.curFillColor = [0.5,0.5,0.5,1.0]; this.curStrokeColor = [0.5,0.5,0.5,1.0]; this.pointSize = 5.0;//default point/stroke return this; }; p5.RendererGL.prototype = Object.create(p5.Renderer.prototype); ////////////////////////////////////////////// // Setting ////////////////////////////////////////////// p5.RendererGL.prototype._initContext = function() { try { this.drawingContext = this.canvas.getContext('webgl', attributes) || this.canvas.getContext('experimental-webgl', attributes); if (this.drawingContext === null) { throw new Error('Error creating webgl context'); } else { console.log('p5.RendererGL: enabled webgl context'); var gl = this.drawingContext; gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LEQUAL); gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); } } catch (er) { throw new Error(er); } }; //detect if user didn't set the camera //then call this function below p5.RendererGL.prototype._setDefaultCamera = function(){ if(this._curCamera === null){ var _w = this.width; var _h = this.height; this.uPMatrix = p5.Matrix.identity(); var cameraZ = (this.height / 2) / Math.tan(Math.PI * 30 / 180); this.uPMatrix.perspective(60 / 180 * Math.PI, _w / _h, cameraZ * 0.1, cameraZ * 10); this._curCamera = 'default'; } }; p5.RendererGL.prototype._update = function() { this.uMVMatrix = p5.Matrix.identity(); this.translate(0, 0, -(this.height / 2) / Math.tan(Math.PI * 30 / 180)); this.ambientLightCount = 0; this.directionalLightCount = 0; this.pointLightCount = 0; }; /** * [background description] */ p5.RendererGL.prototype.background = function() { var gl = this.GL; var _col = this._pInst.color.apply(this._pInst, arguments); var _r = (_col.levels[0]) / 255; var _g = (_col.levels[1]) / 255; var _b = (_col.levels[2]) / 255; var _a = (_col.levels[3]) / 255; gl.clearColor(_r, _g, _b, _a); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); }; //@TODO implement this // p5.RendererGL.prototype.clear = function() { //@TODO // }; ////////////////////////////////////////////// // SHADER ////////////////////////////////////////////// /** * [_initShaders description] * @param {string} vertId [description] * @param {string} fragId [description] * @return {Object} the shader program */ p5.RendererGL.prototype._initShaders = function(vertId, fragId, isImmediateMode) { var gl = this.GL; //set up our default shaders by: // 1. create the shader, // 2. load the shader source, // 3. compile the shader var _vertShader = gl.createShader(gl.VERTEX_SHADER); //load in our default vertex shader gl.shaderSource(_vertShader, shader[vertId]); gl.compileShader(_vertShader); // if our vertex shader failed compilation? if (!gl.getShaderParameter(_vertShader, gl.COMPILE_STATUS)) { alert('Yikes! An error occurred compiling the shaders:' + gl.getShaderInfoLog(_vertShader)); return null; } var _fragShader = gl.createShader(gl.FRAGMENT_SHADER); //load in our material frag shader gl.shaderSource(_fragShader, shader[fragId]); gl.compileShader(_fragShader); // if our frag shader failed compilation? if (!gl.getShaderParameter(_fragShader, gl.COMPILE_STATUS)) { alert('Darn! An error occurred compiling the shaders:' + gl.getShaderInfoLog(_fragShader)); return null; } var shaderProgram = gl.createProgram(); gl.attachShader(shaderProgram, _vertShader); gl.attachShader(shaderProgram, _fragShader); gl.linkProgram(shaderProgram); if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { alert('Snap! Error linking shader program'); } //END SHADERS SETUP this._getLocation(shaderProgram, isImmediateMode); return shaderProgram; }; p5.RendererGL.prototype._getLocation = function(shaderProgram, isImmediateMode) { var gl = this.GL; gl.useProgram(shaderProgram); //projection Matrix uniform shaderProgram.uPMatrixUniform = gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'); //model view Matrix uniform shaderProgram.uMVMatrixUniform = gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'); //@TODO: figure out a better way instead of if statement if(isImmediateMode === undefined){ //normal Matrix uniform shaderProgram.uNMatrixUniform = gl.getUniformLocation(shaderProgram, 'uNormalMatrix'); shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, 'uSampler'); } }; /** * Sets a shader uniform given a shaderProgram and uniform string * @param {String} shaderKey key to material Hash. * @param {String} uniform location in shader. * @param {Number} data data to bind uniform. Float data type. * @chainable * @todo currently this function sets uniform1f data. * Should generalize function to accept any uniform * data type. */ p5.RendererGL.prototype._setUniform1f = function(shaderKey,uniform,data) { var gl = this.GL; var shaderProgram = this.mHash[shaderKey]; gl.useProgram(shaderProgram); shaderProgram[uniform] = gl.getUniformLocation(shaderProgram, uniform); gl.uniform1f(shaderProgram[uniform], data); return this; }; p5.RendererGL.prototype._setMatrixUniforms = function(shaderKey) { var gl = this.GL; var shaderProgram = this.mHash[shaderKey]; gl.useProgram(shaderProgram); gl.uniformMatrix4fv( shaderProgram.uPMatrixUniform, false, this.uPMatrix.mat4); gl.uniformMatrix4fv( shaderProgram.uMVMatrixUniform, false, this.uMVMatrix.mat4); this.uNMatrix.inverseTranspose(this.uMVMatrix); gl.uniformMatrix3fv( shaderProgram.uNMatrixUniform, false, this.uNMatrix.mat3); }; ////////////////////////////////////////////// // GET CURRENT | for shader and color ////////////////////////////////////////////// p5.RendererGL.prototype._getShader = function(vertId, fragId, isImmediateMode) { var mId = vertId + '|' + fragId; //create it and put it into hashTable if(!this.materialInHash(mId)){ var shaderProgram = this._initShaders(vertId, fragId, isImmediateMode); this.mHash[mId] = shaderProgram; } this.curShaderId = mId; return this.mHash[this.curShaderId]; }; p5.RendererGL.prototype._getCurShaderId = function(){ //if the shader ID is not yet defined if(this.drawMode !== 'fill' && this.curShaderId === undefined){ //default shader: normalMaterial() var mId = 'normalVert|normalFrag'; var shaderProgram = this._initShaders('normalVert', 'normalFrag'); this.mHash[mId] = shaderProgram; this.curShaderId = mId; } else if(this.isImmediateDrawing && this.drawMode === 'fill'){ // note that this._getShader will check if the shader already exists // by looking up the shader id (composed of vertexShaderId|fragmentShaderId) // in the material hash. If the material isn't found in the hash, it // creates a new one using this._initShaders--however, we'd like // use the cached version as often as possible, so we defer to this._getShader // here instead of calling this._initShaders directly. this._getShader('immediateVert', 'vertexColorFrag', true); } return this.curShaderId; }; ////////////////////////////////////////////// // COLOR ////////////////////////////////////////////// /** * Basic fill material for geometry with a given color * @method fill * @param {Number|Array|String|p5.Color} v1 gray value, * red or hue value (depending on the current color mode), * or color Array, or CSS color string * @param {Number} [v2] optional: green or saturation value * @param {Number} [v3] optional: blue or brightness value * @param {Number} [a] optional: opacity * @chainable * @example *
* * function setup(){ * createCanvas(100, 100, WEBGL); * } * * function draw(){ * background(0); * fill(250, 0, 0); * rotateX(frameCount * 0.01); * rotateY(frameCount * 0.01); * rotateZ(frameCount * 0.01); * box(200, 200, 200); * } * *
* * @alt * red canvas * */ p5.RendererGL.prototype.fill = function(v1, v2, v3, a) { var gl = this.GL; var shaderProgram; //see material.js for more info on color blending in webgl var colors = this._applyColorBlend.apply(this, arguments); this.curFillColor = colors; this.drawMode = 'fill'; if(this.isImmediateDrawing){ shaderProgram = this._getShader('immediateVert','vertexColorFrag'); gl.useProgram(shaderProgram); } else { shaderProgram = this._getShader('normalVert', 'basicFrag'); gl.useProgram(shaderProgram); //RetainedMode uses a webgl uniform to pass color vals //in ImmediateMode, we want access to each vertex so therefore //we cannot use a uniform. shaderProgram.uMaterialColor = gl.getUniformLocation( shaderProgram, 'uMaterialColor' ); gl.uniform4f( shaderProgram.uMaterialColor, colors[0], colors[1], colors[2], colors[3]); } return this; }; p5.RendererGL.prototype.stroke = function(r, g, b, a) { var color = this._pInst.color.apply(this._pInst, arguments); var colorNormalized = color._array; this.curStrokeColor = colorNormalized; this.drawMode = 'stroke'; return this; }; //@TODO p5.RendererGL.prototype._strokeCheck = function(){ if(this.drawMode === 'stroke'){ throw new Error( 'stroke for shapes in 3D not yet implemented, use fill for now :(' ); } }; /** * [strokeWeight description] * @param {Number} pointSize stroke point size * @chainable * @todo strokeWeight currently works on points only. * implement on all wireframes and strokes. */ p5.RendererGL.prototype.strokeWeight = function(pointSize) { this.pointSize = pointSize; return this; }; ////////////////////////////////////////////// // HASH | for material and geometry ////////////////////////////////////////////// p5.RendererGL.prototype.geometryInHash = function(gId){ return this.gHash[gId] !== undefined; }; p5.RendererGL.prototype.materialInHash = function(mId){ return this.mHash[mId] !== undefined; }; /** * [resize description] * @param {Number} w [description] * @param {Number} h [description] */ p5.RendererGL.prototype.resize = function(w,h) { var gl = this.GL; p5.Renderer.prototype.resize.call(this, w, h); gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); // If we're using the default camera, update the aspect ratio if(this._curCamera === 'default') { this._curCamera = null; this._setDefaultCamera(); } }; /** * clears color and depth buffers * with r,g,b,a * @param {Number} r normalized red val. * @param {Number} g normalized green val. * @param {Number} b normalized blue val. * @param {Number} a normalized alpha val. */ p5.RendererGL.prototype.clear = function() { var gl = this.GL; gl.clearColor(arguments[0], arguments[1], arguments[2], arguments[3]); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); }; /** * [translate description] * @param {Number} x [description] * @param {Number} y [description] * @param {Number} z [description] * @chainable * @todo implement handle for components or vector as args */ p5.RendererGL.prototype.translate = function(x, y, z) { this.uMVMatrix.translate([x,-y,z]); return this; }; /** * Scales the Model View Matrix by a vector * @param {Number | p5.Vector | Array} x [description] * @param {Number} [y] y-axis scalar * @param {Number} [z] z-axis scalar * @chainable */ p5.RendererGL.prototype.scale = function(x,y,z) { this.uMVMatrix.scale([x,y,z]); return this; }; p5.RendererGL.prototype.rotate = function(rad, axis){ this.uMVMatrix.rotate(rad, axis); return this; }; p5.RendererGL.prototype.rotateX = function(rad) { this.rotate(rad, [1,0,0]); return this; }; p5.RendererGL.prototype.rotateY = function(rad) { this.rotate(rad, [0,1,0]); return this; }; p5.RendererGL.prototype.rotateZ = function(rad) { this.rotate(rad, [0,0,1]); return this; }; /** * pushes a copy of the model view matrix onto the * MV Matrix stack. */ p5.RendererGL.prototype.push = function() { uMVMatrixStack.push(this.uMVMatrix.copy()); }; /** * [pop description] */ p5.RendererGL.prototype.pop = function() { if (uMVMatrixStack.length === 0) { throw new Error('Invalid popMatrix!'); } this.uMVMatrix = uMVMatrixStack.pop(); }; p5.RendererGL.prototype.resetMatrix = function() { this.uMVMatrix = p5.Matrix.identity(); this.translate(0, 0, -800); return this; }; // Text/Typography // @TODO: p5.RendererGL.prototype._applyTextProperties = function() { //@TODO finish implementation console.error('text commands not yet implemented in webgl'); }; module.exports = p5.RendererGL; },{"../core/core":5,"../core/p5.Renderer":12,"./p5.Matrix":27,"./shader":29}],29:[function(_dereq_,module,exports){ module.exports = { immediateVert: "attribute vec3 aPosition;\nattribute vec4 aVertexColor;\n\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\nuniform float uResolution;\nuniform float uPointSize;\n\nvarying vec4 vColor;\nvoid main(void) {\n vec4 positionVec4 = vec4(aPosition * vec3(1.0, -1.0, 1.0), 1.0);\n gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;\n vColor = aVertexColor;\n gl_PointSize = uPointSize;\n}\n", vertexColorVert: "attribute vec3 aPosition;\nattribute vec4 aVertexColor;\n\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\n\nvarying vec4 vColor;\n\nvoid main(void) {\n vec4 positionVec4 = vec4(aPosition * vec3(1.0, -1.0, 1.0), 1.0);\n gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;\n vColor = aVertexColor;\n}\n", vertexColorFrag: "precision mediump float;\nvarying vec4 vColor;\nvoid main(void) {\n gl_FragColor = vColor;\n}", normalVert: "attribute vec3 aPosition;\nattribute vec3 aNormal;\nattribute vec2 aTexCoord;\n\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\nuniform mat3 uNormalMatrix;\n\nvarying vec3 vVertexNormal;\nvarying highp vec2 vVertTexCoord;\n\nvoid main(void) {\n vec4 positionVec4 = vec4(aPosition * vec3(1.0, -1.0, 1.0), 1.0);\n gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;\n vVertexNormal = vec3( uNormalMatrix * aNormal );\n vVertTexCoord = aTexCoord;\n}\n", normalFrag: "precision mediump float;\nvarying vec3 vVertexNormal;\nvoid main(void) {\n gl_FragColor = vec4(vVertexNormal, 1.0);\n}", basicFrag: "precision mediump float;\nvarying vec3 vVertexNormal;\nuniform vec4 uMaterialColor;\nvoid main(void) {\n gl_FragColor = uMaterialColor;\n}", lightVert: "attribute vec3 aPosition;\nattribute vec3 aNormal;\nattribute vec2 aTexCoord;\n\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\nuniform mat3 uNormalMatrix;\nuniform int uAmbientLightCount;\nuniform int uDirectionalLightCount;\nuniform int uPointLightCount;\n\nuniform vec3 uAmbientColor[8];\nuniform vec3 uLightingDirection[8];\nuniform vec3 uDirectionalColor[8];\nuniform vec3 uPointLightLocation[8];\nuniform vec3 uPointLightColor[8];\nuniform bool uSpecular;\n\nvarying vec3 vVertexNormal;\nvarying vec2 vVertTexCoord;\nvarying vec3 vLightWeighting;\n\nvec3 ambientLightFactor = vec3(0.0, 0.0, 0.0);\nvec3 directionalLightFactor = vec3(0.0, 0.0, 0.0);\nvec3 pointLightFactor = vec3(0.0, 0.0, 0.0);\nvec3 pointLightFactor2 = vec3(0.0, 0.0, 0.0);\n\nvoid main(void){\n\n vec4 positionVec4 = vec4(aPosition, 1.0);\n gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;\n\n vec3 vertexNormal = vec3( uNormalMatrix * aNormal );\n vVertexNormal = vertexNormal;\n vVertTexCoord = aTexCoord;\n\n vec4 mvPosition = uModelViewMatrix * vec4(aPosition, 1.0);\n vec3 eyeDirection = normalize(-mvPosition.xyz);\n\n float shininess = 32.0;\n float specularFactor = 2.0;\n float diffuseFactor = 0.3;\n\n for(int i = 0; i < 8; i++){\n if(uAmbientLightCount == i) break;\n ambientLightFactor += uAmbientColor[i];\n }\n\n for(int j = 0; j < 8; j++){\n if(uDirectionalLightCount == j) break;\n vec3 dir = uLightingDirection[j];\n float directionalLightWeighting = max(dot(vertexNormal, dir), 0.0);\n directionalLightFactor += uDirectionalColor[j] * directionalLightWeighting;\n }\n\n for(int k = 0; k < 8; k++){\n if(uPointLightCount == k) break;\n vec3 loc = uPointLightLocation[k];\n vec3 lightDirection = normalize(loc - mvPosition.xyz);\n\n float directionalLightWeighting = max(dot(vertexNormal, lightDirection), 0.0);\n pointLightFactor += uPointLightColor[k] * directionalLightWeighting;\n\n //factor2 for specular\n vec3 reflectionDirection = reflect(-lightDirection, vertexNormal);\n float specularLightWeighting = pow(max(dot(reflectionDirection, eyeDirection), 0.0), shininess);\n\n pointLightFactor2 += uPointLightColor[k] * (specularFactor * specularLightWeighting\n + directionalLightWeighting * diffuseFactor);\n }\n\n if(!uSpecular){\n vLightWeighting = ambientLightFactor + directionalLightFactor + pointLightFactor;\n }else{\n vLightWeighting = ambientLightFactor + directionalLightFactor + pointLightFactor2;\n }\n\n}\n", lightTextureFrag: "precision mediump float;\n\nuniform vec4 uMaterialColor;\nuniform sampler2D uSampler;\nuniform bool isTexture;\n\nvarying vec3 vLightWeighting;\nvarying highp vec2 vVertTexCoord;\n\nvoid main(void) {\n if(!isTexture){\n gl_FragColor = vec4(vec3(uMaterialColor.rgb * vLightWeighting), uMaterialColor.a);\n }else{\n vec4 textureColor = texture2D(uSampler, vVertTexCoord);\n if(vLightWeighting == vec3(0., 0., 0.)){\n gl_FragColor = textureColor;\n }else{\n gl_FragColor = vec4(vec3(textureColor.rgb * vLightWeighting), textureColor.a);\n }\n }\n}" }; },{}]},{},[5,10,11,13,23,4,7,21,20,25,22,26,14,1,2,6,18,16,17,9])(26) });