/* P R O C E S S I N G - 0 . 4 . J S a port of the Processing visualization language License : MIT Developer : John Resig: http://ejohn.org Web Site : http://processingjs.org Java Version : http://processing.org Github Repo. : http://github.com/jeresig/processing-js Bug Tracking : http://processing-js.lighthouseapp.com Mozilla POW! : http://wiki.Mozilla.org/Education/Projects/ProcessingForTheWeb Maintained by : Seneca: http://zenit.senecac.on.ca/wiki/index.php/Processing.js Hyper-Metrix: http://hyper-metrix.com/#Processing */ (function(){ // Attach Processing to the window this.Processing = function Processing( processing_code ){ echo("initialising Processing interpreter"); // Build an Processing functions and env. vars into 'p' var p = buildProcessing( ); // Send aCode Processing syntax to be converted to JavaScript if( processing_code ){ p.init( processing_code ); } return p; }; // Parse Processing (Java-like) syntax to JavaScript syntax with Regex var parse = Processing.parse = function parse( aCode, p ){ // Remove end-of-line comments aCode = aCode.replace(/\/\/ .*\n/g, "\n"); // Weird parsing errors with % aCode = aCode.replace(/([^\s])%([^\s])/g, "$1 % $2"); // Since frameRate() and frameRate are different things, // we need to differentiate them somehow. So when we parse // the Processing.js source, replace frameRate so it isn't // confused with frameRate(). aCode = aCode.replace(/(\s*=\s*|\(*\s*)frameRate(\s*\)+?|\s*;)/, "$1p.FRAME_RATE$2"); // Simple convert a function-like thing to function aCode = aCode.replace(/(?:static )?(\w+(?:\[\])* )(\w+)\s*(\([^\)]*\)\s*\{)/g, function (all, type, name, args) { if (name === "if" || name === "for" || name === "while") { return all; } else { return "Processing." + name + " = function " + name + args; } }); // Attach import() to p{} bypassing JS command, allowing for extrernal library loading aCode = aCode.replace(/import \(|import\(/g, "p.Import("); // Force .length() to be .length aCode = aCode.replace(/\.length\(\)/g, ".length"); // foo( int foo, float bar ) aCode = aCode.replace(/([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g, "$1$4"); aCode = aCode.replace(/([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g, "$1$4"); // float[] foo = new float[5]; aCode = aCode.replace(/new (\w+)((?:\[([^\]]*)\])+)/g, function (all, name, args) { return "new ArrayList(" + args.replace(/\[\]/g, "[0]").slice(1, -1).split("][").join(", ") + ")"; //return "new ArrayList(" + args.slice(1, -1).split("][").join(", ") + ")"; }); // What does this do? This does the same thing as "Fix Array[] foo = {...} to [...]" below aCode = aCode.replace(/(?:static )?\w+\[\]\s*(\w+)\[?\]?\s*=\s*\{.*?\};/g, function (all) { return all.replace(/\{/g, "[").replace(/\}/g, "]"); }); // int|float foo; var intFloat = /(\n\s*(?:int|float)(?!\[\])*(?:\s*|[^\(;]*?,\s*))([a-zA-Z]\w*)\s*(,|;)/i; while (intFloat.test(aCode)) { aCode = aCode.replace(new RegExp(intFloat), function (all, type, name, sep) { return type + " " + name + " = 0" + sep; }); } // float foo = 5; aCode = aCode.replace(/(?:static\s+)?(?:final\s+)?(\w+)((?:\[\])+| ) *(\w+)\[?\]?(\s*[=,;])/g, function (all, type, arr, name, sep) { if (type === "return") { return all; } else { return "var " + name + sep; } }); // Fix Array[] foo = {...} to [...] aCode = aCode.replace(/\=\s*\{((.|\s)*?)\};/g, function (all, data) { return "= [" + data.replace(/\{/g, "[").replace(/\}/g, "]") + "]"; }); // super() is a reserved word aCode = aCode.replace(/super\(/g, "superMethod("); var classes = ["int", "float", "boolean", "String", "byte", "double", "long"]; var classReplace = function (all, name, extend, vars, last) { classes.push(name); var staticVar = ""; vars = vars.replace(/final\s+var\s+(\w+\s*=\s*.*?;)/g, function (all, set) { staticVar += " " + name + "." + set; return ""; }); // Move arguments up from constructor and wrap contents with // a with(this), and unwrap constructor return "function " + name + "() {with(this){\n " + (extend ? "var __self=this;function superMethod(){extendClass(__self,arguments," + extend + ");}\n" : "") + // Replace var foo = 0; with this.foo = 0; // and force var foo; to become this.foo = null; vars.replace(/\s*,\s*/g, ";\n this.").replace(/\b(var |final |public )+\s*/g, "this.").replace(/\b(var |final |public )+\s*/g, "this.").replace(/this\.(\w+);/g, "this.$1 = null;") + (extend ? "extendClass(this, " + extend + ");\n" : "") + "" + (typeof last === "string" ? last : name + "("); }; var nextBrace = function (right) { var rest = right, position = 0, leftCount = 1, rightCount = 0; while (leftCount !== rightCount) { var nextLeft = rest.indexOf("{"), nextRight = rest.indexOf("}"); if (nextLeft < nextRight && nextLeft !== -1) { leftCount++; rest = rest.slice(nextLeft + 1); position += nextLeft + 1; } else { rightCount++; rest = rest.slice(nextRight + 1); position += nextRight + 1; } } return right.slice(0, position - 1); }; var matchClasses = /(?:public |abstract |static )*class (\w+)\s*(?:extends\s*(\w+)\s*)?\{\s*((?:.|\n)*?)\b\1\s*\(/g; var matchNoCon = /(?:public |abstract |static )*class (\w+)\s*(?:extends\s*(\w+)\s*)?\{\s*((?:.|\n)*?)(Processing)/g; aCode = aCode.replace(matchClasses, classReplace); aCode = aCode.replace(matchNoCon, classReplace); var matchClass = //, m; while ((m = aCode.match(matchClass))) { var left = RegExp.leftContext, allRest = RegExp.rightContext, rest = nextBrace(allRest), className = m[1], staticVars = m[2] || ""; allRest = allRest.slice(rest.length + 1); rest = rest.replace(new RegExp("\\b" + className + "\\(([^\\)]*?)\\)\\s*{", "g"), function (all, args) { args = args.split(/,\s*?/); if (args[0].match(/^\s*$/)) { args.shift(); } var fn = "if ( arguments.length === " + args.length + " ) {\n"; for (var i = 0; i < args.length; i++) { fn += " var " + args[i] + " = arguments[" + i + "];\n"; } return fn; }); // Fix class method names // this.collide = function() { ... } // and add closing } for with(this) ... rest = rest.replace(/(?:public )?Processing.\w+ = function (\w+)\((.*?)\)/g, function (all, name, args) { return "ADDMETHOD(this, '" + name + "', function(" + args + ")"; }); var matchMethod = /ADDMETHOD([\s\S]*?\{)/, mc; var methods = ""; while ((mc = rest.match(matchMethod))) { var prev = RegExp.leftContext, allNext = RegExp.rightContext, next = nextBrace(allNext); methods += "addMethod" + mc[1] + next + "});"; rest = prev + allNext.slice(next.length + 1); } rest = methods + rest; aCode = left + rest + "\n}}" + staticVars + allRest; } // Do some tidying up, where necessary aCode = aCode.replace(/Processing.\w+ = function addMethod/g, "addMethod"); // Check if 3D context is invoked -- this is not the best way to do this. if (aCode.match(/size\((?:.+),(?:.+),\s*OPENGL\);/)) { p.use3DContext = true; } // Handle (int) Casting aCode = aCode.replace(/\(int\)/g, "0|"); // Remove Casting aCode = aCode.replace(new RegExp("\\((" + classes.join("|") + ")(\\[\\])*\\)", "g"), ""); // Force numbers to exist // //aCode = aCode.replace(/([^.])(\w+)\s*\+=/g, "$1$2 = ($2||0) +"); //! // Force characters-as-bytes to work --> Ping: Andor aCode = aCode.replace(/('[a-zA-Z0-9]')/g, "$1.charCodeAt(0)"); var toNumbers = function (str) { var ret = []; str.replace(/(..)/g, function (str) { ret.push(parseInt(str, 16)); }); return ret; }; // Convert #aaaaaa into color aCode = aCode.replace(/#([a-f0-9]{6})/ig, function (m, hex) { var num = toNumbers(hex); return "DefaultColor(" + num[0] + "," + num[1] + "," + num[2] + ")"; }); // Convert 3.0f to just 3.0 aCode = aCode.replace(/(\d+)f/g, "$1"); return aCode; }; // Attach Processing functions to 'p' function buildProcessing( freej_screen ){ // Create the 'p' object var p = {}; // Set Processing defaults / environment variables p.name = 'Processing.js Instance'; p.PI = Math.PI; p.TWO_PI = 2 * p.PI; p.HALF_PI = p.PI / 2; p.P3D = 3; p.CORNER = 0; p.RADIUS = 1; p.CENTER_RADIUS = 1; p.CENTER = 2; p.POLYGON = 2; p.QUADS = 5; p.TRIANGLES = 6; p.POINTS = 7; p.LINES = 8; p.TRIANGLE_STRIP = 9; p.TRIANGLE_FAN = 4; p.QUAD_STRIP = 3; p.CORNERS = 10; p.CLOSE = true; p.RGB = 1; p.HSB = 2; p.focused = true; // KeyCode table p.CENTER = 88888880; p.CODED = 88888888; p.UP = 88888870; p.RIGHT = 88888871; p.DOWN = 88888872; p.LEFT = 88888869; //! // Description required... p.codedKeys = [ 69, 70, 71, 72 ]; // "Private" variables used to maintain state var online = true, doFill = true, doStroke = true, loopStarted = false, hasBackground = false, doLoop = true, looping = 0, curRectMode = p.CORNER, curEllipseMode = p.CENTER, inSetup = false, inDraw = false, curBackground = "rgba( 204, 204, 204, 1 )", curFrameRate = 1000, curCursor = p.ARROW, // oldCursor = document.body.style.cursor, curMsPerFrame = 1, curShape = p.POLYGON, curShapeCount = 0, curvePoints = [], curTightness = 0, opacityRange = 255, redRange = 255, greenRange = 255, blueRange = 255, pathOpen = false, mousePressed = false, keyPressed = false, curColorMode = p.RGB, curTint = -1, curTextSize = 12, curTextFont = "Arial", getLoaded = false, start = new Date().getTime(), timeSinceLastFPS = start, framesSinceLastFPS = 0; var firstX, firstY, secondX, secondY, prevX, prevY; // Stores states for pushStyle() and popStyle(). var styleArray = new Array(0); // Store a line for println(), print() handline p.ln = ""; // Glyph path storage for textFonts p.glyphTable = {}; // Global vars for tracking mouse position p.pmouseX = 0; p.pmouseY = 0; p.mouseX = 0; p.mouseY = 0; p.mouseButton = 0; p.mouseDown = false; // Undefined event handlers to be replaced by user when needed p.mouseClicked = undefined; p.mouseDragged = undefined; p.mouseMoved = undefined; p.mousePressed = undefined; p.mouseReleased = undefined; p.keyPressed = undefined; p.keyReleased = undefined; p.draw = undefined; p.setup = undefined; // The height/width of the canvas // p.width = curElement.width - 0; // p.height = curElement.height - 0; // no need to restrict the size to the screen in freej // since a layer can be bigger than that... // The current animation frame p.frameCount = 0; //////////////////////////////////////////////////////////////////////////// // Array handling //////////////////////////////////////////////////////////////////////////// p.split = function (str, delim) { return str.split(delim); }; p.splitTokens = function (str, tokens) { if (arguments.length === 1) { tokens = "\n\t\r\f "; } tokens = "[" + tokens + "]"; var ary = new Array(0); var index = 0; var pos = str.search(tokens); while (pos >= 0) { if (pos === 0) { str = str.substring(1); } else { ary[index] = str.substring(0, pos); index++; str = str.substring(pos); } pos = str.search(tokens); } if (str.length > 0) { ary[index] = str; } if (ary.length === 0) { ary = undefined; } return ary; }; p.append = function (array, element) { array[array.length] = element; return array; }; p.concat = function concat(array1, array2) { return array1.concat(array2); }; p.splice = function (array, value, index) { if (array.length === 0 && value.length === 0) { return array; } if (value instanceof Array) { for (var i = 0, j = index; i < value.length; j++, i++) { array.splice(j, 0, value[i]); } } else { array.splice(index, 0, value); } return array; }; p.subset = function (array, offset, length) { if (arguments.length === 2) { return p.subset(array, offset, array.length - offset); } else if (arguments.length === 3) { return array.slice(offset, offset + length); } }; p.join = function join(array, seperator) { return array.join(seperator); }; p.shorten = function (ary) { var newary = new Array(0); // copy array into new array var len = ary.length; for (var i = 0; i < len; i++) { newary[i] = ary[i]; } newary.pop(); return newary; }; p.expand = function (ary, newSize) { var newary = new Array(0); var len = ary.length; for (var i = 0; i < len; i++) { newary[i] = ary[i]; } if (arguments.length === 1) { // double size of array newary.length *= 2; } else if (arguments.length === 2) { // size is newSize newary.length = newSize; } return newary; }; p.ArrayList = function ArrayList(size, size2, size3) { var array = new Array(0 | size); if (size2) { for (var i = 0; i < size; i++) { array[i] = []; for (var j = 0; j < size2; j++) { var a = array[i][j] = size3 ? new Array(size3) : 0; for (var k = 0; k < size3; k++) { a[k] = 0; } } } } else { for (var l = 0; l < size; l++) { array[l] = 0; } } array.get = function( i ){ return this[ i ]; }; array.add = function( item ){ return this.push( item ); }; array.size = function( ){ return this.length; }; array.clear = function( ){ this.length = 0; }; array.remove = function( i ){ return this.splice( i, 1 ); }; array.isEmpty = function( ){ return !this.length; }; array.clone = function( ){ var a = new ArrayList( size ); for( var i = 0; i < size; i++ ){ a[ i ] = this[ i ]; } return a; }; return array; }; p.reverse = function (array) { return array.reverse(); }; //////////////////////////////////////////////////////////////////////////// // Color functions //////////////////////////////////////////////////////////////////////////// // convert rgba color strings to integer p.rgbaToInt = function (color) { var rgbaAry = /\(([^\)]+)\)/.exec(color).slice(1, 2)[0].split(','); return ((rgbaAry[3] * 255) << 24) | (rgbaAry[0] << 16) | (rgbaAry[1] << 8) | (rgbaAry[2]); }; // helper functions for internal blending modes p.mix = function (a, b, f) { return a + (((b - a) * f) >> 8); }; p.peg = function (n) { return (n < 0) ? 0 : ((n > 255) ? 255 : n); }; // blending modes p.modes = { replace: function (a, b) { return p.rgbaToInt(b); }, blend: function (a, b) { var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | p.mix(c1 & p.RED_MASK, c2 & p.RED_MASK, f) & p.RED_MASK | p.mix(c1 & p.GREEN_MASK, c2 & p.GREEN_MASK, f) & p.GREEN_MASK | p.mix(c1 & p.BLUE_MASK, c2 & p.BLUE_MASK, f)); }, add: function (a, b) { var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | Math.min(((c1 & p.RED_MASK) + ((c2 & p.RED_MASK) >> 8) * f), p.RED_MASK) & p.RED_MASK | Math.min(((c1 & p.GREEN_MASK) + ((c2 & p.GREEN_MASK) >> 8) * f), p.GREEN_MASK) & p.GREEN_MASK | Math.min((c1 & p.BLUE_MASK) + (((c2 & p.BLUE_MASK) * f) >> 8), p.BLUE_MASK)); }, subtract: function (a, b) { var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | Math.max(((c1 & p.RED_MASK) - ((c2 & p.RED_MASK) >> 8) * f), p.GREEN_MASK) & p.RED_MASK | Math.max(((c1 & p.GREEN_MASK) - ((c2 & p.GREEN_MASK) >> 8) * f), p.BLUE_MASK) & p.GREEN_MASK | Math.max((c1 & p.BLUE_MASK) - (((c2 & p.BLUE_MASK) * f) >> 8), 0)); }, lightest: function (a, b) { var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | Math.max(c1 & p.RED_MASK, ((c2 & p.RED_MASK) >> 8) * f) & p.RED_MASK | Math.max(c1 & p.GREEN_MASK, ((c2 & p.GREEN_MASK) >> 8) * f) & p.GREEN_MASK | Math.max(c1 & p.BLUE_MASK, ((c2 & p.BLUE_MASK) * f) >> 8)); }, darkest: function (a, b) { var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | p.mix(c1 & p.RED_MASK, Math.min(c1 & p.RED_MASK, ((c2 & p.RED_MASK) >> 8) * f), f) & p.RED_MASK | p.mix(c1 & p.GREEN_MASK, Math.min(c1 & p.GREEN_MASK, ((c2 & p.GREEN_MASK) >> 8) * f), f) & p.GREEN_MASK | p.mix(c1 & p.BLUE_MASK, Math.min(c1 & p.BLUE_MASK, ((c2 & p.BLUE_MASK) * f) >> 8), f)); }, difference: function (a, b) { var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = (ar > br) ? (ar - br) : (br - ar); var cg = (ag > bg) ? (ag - bg) : (bg - ag); var cb = (ab > bb) ? (ab - bb) : (bb - ab); // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)))); }, exclusion: function (a, b) { var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = ar + br - ((ar * br) >> 7); var cg = ag + bg - ((ag * bg) >> 7); var cb = ab + bb - ((ab * bb) >> 7); // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)))); }, multiply: function (a, b) { var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = (ar * br) >> 8; var cg = (ag * bg) >> 8; var cb = (ab * bb) >> 8; // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)))); }, screen: function (a, b) { var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = 255 - (((255 - ar) * (255 - br)) >> 8); var cg = 255 - (((255 - ag) * (255 - bg)) >> 8); var cb = 255 - (((255 - ab) * (255 - bb)) >> 8); // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)))); }, hard_light: function (a, b) { var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = (br < 128) ? ((ar * br) >> 7) : (255 - (((255 - ar) * (255 - br)) >> 7)); var cg = (bg < 128) ? ((ag * bg) >> 7) : (255 - (((255 - ag) * (255 - bg)) >> 7)); var cb = (bb < 128) ? ((ab * bb) >> 7) : (255 - (((255 - ab) * (255 - bb)) >> 7)); // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)))); }, soft_light: function (a, b) { var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = ((ar * br) >> 7) + ((ar * ar) >> 8) - ((ar * ar * br) >> 15); var cg = ((ag * bg) >> 7) + ((ag * ag) >> 8) - ((ag * ag * bg) >> 15); var cb = ((ab * bb) >> 7) + ((ab * ab) >> 8) - ((ab * ab * bb) >> 15); // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)))); }, overlay: function (a, b) { var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = (ar < 128) ? ((ar * br) >> 7) : (255 - (((255 - ar) * (255 - br)) >> 7)); var cg = (ag < 128) ? ((ag * bg) >> 7) : (255 - (((255 - ag) * (255 - bg)) >> 7)); var cb = (ab < 128) ? ((ab * bb) >> 7) : (255 - (((255 - ab) * (255 - bb)) >> 7)); // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)))); }, dodge: function (a, b) { var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = (br === 255) ? 255 : p.peg((ar << 8) / (255 - br)); // division requires pre-peg()-ing var cg = (bg === 255) ? 255 : p.peg((ag << 8) / (255 - bg)); // " var cb = (bb === 255) ? 255 : p.peg((ab << 8) / (255 - bb)); // " // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)))); }, burn: function (a, b) { var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = (br === 0) ? 0 : 255 - p.peg(((255 - ar) << 8) / br); // division requires pre-peg()-ing var cg = (bg === 0) ? 0 : 255 - p.peg(((255 - ag) << 8) / bg); // " var cb = (bb === 0) ? 0 : 255 - p.peg(((255 - ab) << 8) / bb); // " // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)))); } }; // our own freej color function -jrml p.color = function() { p.context.set_color.apply(p.context, arguments); } // !! WARNING: brightness() & saturation() not working with HSB colors p.brightness = function brightness(){ return p.color( redRange, greenRange, blueRange ); } p.saturation = function saturation( color ){ return p.color( ( 126 / 255 ) * redRange, ( 126 / 255 ) * greenRange, ( 126 / 255 ) * blueRange ); } p.hue = function hue(){ return p.color( 0 * redRange, 0 * greenRange, 0 * blueRange ); } // In case I ever need to do HSV conversion: // http://srufaculty.sru.edu/david.dailey/javascript/js/5rml.js p.color_old = function color( aValue1, aValue2, aValue3, aValue4 ) { var aColor = ""; if ( arguments.length == 3 ) { aColor = p.color( aValue1, aValue2, aValue3, opacityRange ); } else if ( arguments.length == 4 ) { var a = aValue4 / opacityRange; a = isNaN(a) ? 1 : a; if ( curColorMode == p.HSB ) { var rgb = HSBtoRGB(aValue1, aValue2, aValue3); var r = rgb[0], g = rgb[1], b = rgb[2]; } else { var r = getColor(aValue1, redRange); var g = getColor(aValue2, greenRange); var b = getColor(aValue3, blueRange); } aColor = "rgba(" + r + "," + g + "," + b + "," + a + ")"; } else if ( typeof aValue1 == "string" ) { aColor = aValue1; if ( arguments.length == 2 ) { var c = aColor.split(","); c[3] = (aValue2 / opacityRange) + ")"; aColor = c.join(","); } } else if ( arguments.length == 2 ) { aColor = p.color( aValue1, aValue1, aValue1, aValue2 ); } else if ( typeof aValue1 == "number" && aValue1 < 256 && aValue1 >= 0) { aColor = p.color( aValue1, aValue1, aValue1, opacityRange ); } else if ( typeof aValue1 == "number" ) { var intcolor = 0; if( aValue1 < 0 ){ intcolor = 4294967296 - ( aValue1 * -1 ); }else{ intcolor = aValue1; } var ac = Math.floor((intcolor % 4294967296) / 16777216); var rc = Math.floor((intcolor % 16777216) / 65536); var gc = Math.floor((intcolor % 65536) / 256); var bc = intcolor % 256; aColor = p.color( rc, gc, bc, ac ); } else { aColor = p.color( redRange, greenRange, blueRange, opacityRange ); } // HSB conversion function from Mootools, MIT Licensed function HSBtoRGB(h, s, b) { h = (h / redRange) * 360; s = (s / greenRange) * 100; b = (b / blueRange) * 100; var br = Math.round(b / 100 * 255); if (s == 0){ return [br, br, br]; } else { var hue = h % 360; var f = hue % 60; var p = Math.round((b * (100 - s)) / 10000 * 255); var q = Math.round((b * (6000 - s * f)) / 600000 * 255); var t = Math.round((b * (6000 - s * (60 - f))) / 600000 * 255); switch (Math.floor(hue / 60)){ case 0: return [br, t, p]; case 1: return [q, br, p]; case 2: return [p, br, t]; case 3: return [p, q, br]; case 4: return [t, p, br]; case 5: return [br, p, q]; } } } function getColor( aValue, range ) { return Math.round(255 * (aValue / range)); } return aColor; } p.red = function( aColor ){ return parseInt( verifyChannel( aColor ).slice( 5 ) ); }; p.green = function( aColor ){ return parseInt( verifyChannel( aColor ).split( "," )[ 1 ] ); }; p.blue = function( aColor ){ return parseInt( verifyChannel( aColor ).split( "," )[ 2 ] ); }; p.alpha = function( aColor ){ return parseInt( parseFloat( verifyChannel( aColor ).split( "," )[ 3 ] ) * 255 ); }; function verifyChannel( aColor ){ if( aColor.constructor == Array ){ return aColor; } else { return p.color( aColor ); } } p.lerpColor = function lerpColor( c1, c2, amt ){ // Get RGBA values for Color 1 to floats var colors1 = p.color( c1 ).split( "," ); var r1 = parseInt( colors1[ 0 ].split( "(" )[ 1 ] ); var g1 = parseInt( colors1[ 1 ] ); var b1 = parseInt( colors1[ 2 ] ); var a1 = parseFloat( colors1[ 3 ].split( ")" )[ 0 ] ); // Get RGBA values for Color 2 to floats var colors2 = p.color( c2 ).split( "," ); var r2 = parseInt( colors2[ 0 ].split( "(" )[ 1 ] ); var g2 = parseInt( colors2[ 1 ] ); var b2 = parseInt( colors2[ 2 ] ); var a2 = parseFloat( colors2[ 3 ].split( ")" )[ 0 ] ); // Return lerp value for each channel, INT for color, Float for Alpha-range var r = parseInt( p.lerp( r1, r2, amt ) ); var g = parseInt( p.lerp( g1, g2, amt ) ); var b = parseInt( p.lerp( b1, b2, amt ) ); var a = parseFloat( p.lerp( a1, a2, amt ) ); return aColor = "rgba("+ r +","+ g +","+ b +","+ a +")"; } // Forced default color mode for #aaaaaa style p.DefaultColor = function( aValue1, aValue2, aValue3 ){ var tmpColorMode = curColorMode; curColorMode = p.RGB; var c = p.color(aValue1 / 255 * redRange, aValue2 / 255 * greenRange, aValue3 / 255 * blueRange ); curColorMode = tmpColorMode; return c; } p.colorMode = function colorMode( mode, range1, range2, range3, range4 ){ curColorMode = mode; if( arguments.length >= 4 ){ redRange = range1; greenRange = range2; blueRange = range3; } if( arguments.length == 5 ){ opacityRange = range4; } if( arguments.length == 2 ){ p.colorMode( mode, range1, range1, range1, range1 ); } }; //////////////////////////////////////////////////////////////////////////// // Canvas-Matrix manipulation //////////////////////////////////////////////////////////////////////////// p.translate = function translate( x, y ){ p.context.translate( x, y ); }; p.scale = function scale( x, y ) { p.context.scale( x, y || x ); }; p.rotate = function rotate( aAngle ) { p.context.rotate( aAngle ); }; p.pushMatrix = function pushMatrix() { p.context.save(); }; p.popMatrix = function popMatrix() { p.context.restore(); }; p.ortho = function ortho(){}; //////////////////////////////////////////////////////////////////////////// //Time based functions //////////////////////////////////////////////////////////////////////////// p.year = function year() { return ( new Date ).getYear() + 1900; }; p.month = function month() { return ( new Date ).getMonth(); }; p.day = function day() { return ( new Date ).getDay(); }; p.hour = function hour() { return ( new Date ).getHours(); }; p.minute = function minute(){ return ( new Date ).getMinutes(); }; p.second = function second(){ return ( new Date ).getSeconds(); }; p.millis = function millis(){ return ( new Date ) .getTime() - start; }; p.noLoop = function noLoop(){ doLoop = false; }; p.redraw = function redraw(){ if( hasBackground ){ p.background(); } p.frameCount++; inDraw = true; p.pushMatrix(); p.draw(); p.popMatrix(); inDraw = false; }; p.loop = function loop(){ if( loopStarted ){ return; } looping = new TriggerController(); register_controller(looping) looping.frame = function() { p.redraw(); } loopStarter = true; }; p.frameRate = function frameRate( aRate ){ // curFrameRate = aRate; // curMsPerFrame = 1000 / curFrameRate; set_fps( aRate ); }; p.exit = function exit(){ clearInterval( looping ); }; //////////////////////////////////////////////////////////////////////////// // MISC functions //////////////////////////////////////////////////////////////////////////// p.cursor = function(mode){ document.body.style.cursor=mode; } p.link = function( href, target ) { window.location = href; }; p.beginDraw = function beginDraw(){}; p.endDraw = function endDraw(){}; // p.disableContextMenu = function disableContextMenu(){ // curElement.addEventListener( 'contextmenu', function( e ){ // e.preventDefault(); // e.stopPropagation(); // }, false ); // } //////////////////////////////////////////////////////////////////////////// // Binary Functions //////////////////////////////////////////////////////////////////////////// p.unbinary = function unbinary(binaryString) { var binaryPattern = new RegExp("^[0|1]{8}$"); var addUp = 0; if (isNaN(binaryString)) { throw "NaN_Err"; } else { if (arguments.length === 1 || binaryString.length === 8) { if (binaryPattern.test(binaryString)) { for (i = 0; i < 8; i++) { addUp += (Math.pow(2, i) * parseInt(binaryString.charAt(7 - i), 10)); } return addUp + ""; } else { throw "notBinary: the value passed into unbinary was not an 8 bit binary number"; } } else { throw "longErr"; } } return addUp; }; p.nfs = function (num, left, right) { var str, len; // array handling if (typeof num === "object") { str = new Array(0); len = num.length; for (var i = 0; i < len; i++) { str[i] = p.nfs(num[i], left, right); } } else if (arguments.length === 3) { var negative = false; if (num < 0) { negative = true; } str = "" + Math.abs(num); var digits = ("" + Math.floor(Math.abs(num))).length; var count = left - digits; while (count > 0) { str = "0" + str; count--; } // get the number of decimal places, if none will be -1 var decimals = ("" + Math.abs(num)).length - digits - 1; if (decimals === -1 && right > 0) { str = str + "."; } if (decimals !== -1) { count = right - decimals; } else if (decimals === -1 && right > 0) { count = right; } else { count = 0; } while (count > 0) { str = str + "0"; count--; } str = (negative ? "-" : " ") + str; } else if (arguments.length === 2) { str = p.nfs(num, left, 0); } return str; }; p.nfc = function (num, right) { var str; var decimals = right >= 0 ? right : 0; if (typeof num === "object") { str = new Array(0); for (var i = 0; i < num.length; i++) { str[i] = p.nfc(num[i], decimals); } } else if (arguments.length === 2) { var rawStr = p.nfs(num, 0, decimals); var ary = new Array(0); ary = rawStr.split('.'); // ary[0] contains left of decimal, ary[1] contains decimal places if they exist // insert commas now, then append ary[1] if it exists var leftStr = ary[0]; var rightStr = ary.length > 1 ? '.' + ary[1] : ''; var commas = /(\d+)(\d{3})/; while (commas.test(leftStr)) { leftStr = leftStr.replace(commas, '$1' + ',' + '$2'); } str = leftStr + rightStr; } else if (arguments.length === 1) { str = p.nfc(num, 0); } return str; }; //function i use to convert decimals to a padded hex value p.decimalToHex = function decimalToHex(d, padding) { //if there is no padding value added, default padding to 8 else go into while statement. padding = typeof(padding) === "undefined" || padding === null ? padding = 8 : padding; var hex = Number(d).toString(16); while (hex.length < padding) { hex = "0" + hex; } return hex; }; //regExp i made to pattern match rgba and extract it's values p.colorRGB = function colorRGB(col) { var patt = /^rgba?\((\d{1,3}),(\d{1,3}),(\d{1,3}),?(\d{0,3})\)$/i; //grouped \d{1,3} with ( ) so they can be referenced w\ $1-$4 // What's up with the crazy variable names? -F1LT3R var al = col.replace(patt, "$4"); var reD = col.replace(patt, "$1"); var gree = col.replace(patt, "$2"); var blu = col.replace(patt, "$3"); return ("" + Number(al).toString(16) + Number(reD).toString(16) + Number(gree).toString(16) + Number(blu).toString(16)).toUpperCase(); }; p.hex = function hex(decimal, len) { var hexadecimal = ""; var patternRGBa = /^rgba?\((\d{1,3}),(\d{1,3}),(\d{1,3}),?(\d{0,3})\)$/i; //match rgba(20,20,20,0) or rgba(20,20,20) var patternDigits = /^\d+$/; //************************** dealing with 2 parameters ************************************************* if (arguments.length === 2) { if (patternDigits.test(decimal)) { hexadecimal = p.decimalToHex(decimal, len); } else if (patternRGBa.test(decimal)) //check to see if it's an rgba color { hexadecimal = p.colorRGB(decimal); hexadecimal = hexadecimal.substring(hexadecimal.length - len, hexadecimal.length); } } else if (arguments.length === 1) //**************** dealing with 1 parameter ******************************** { if (patternDigits.test(decimal)) { //check to see if it's a decimal hexadecimal = p.decimalToHex(decimal); } else if (patternRGBa.test(decimal)) //check to see if it's an rgba color { hexadecimal = p.colorRGB(decimal); } else if (decimal.indexOf("#") === 0) //check to see if it's hex color in format #ffffff { if (decimal.length < 7) { throw "Not Hex format: the value passed into hex was not in the format #FFFFFF"; } else { decimal = (decimal.slice(1)).toUpperCase(); while (decimal.length < 8) { decimal = "FF" + decimal; } hexadecimal = decimal; } } } return hexadecimal; }; p.unhex = function (str) { var value = 0, multiplier = 1, num = 0; var len = str.length - 1; for (var i = len ; i >= 0; i--){ switch(str[i]){ case "0": num = 0; break; case "1": num = 1; break; case "2": num = 2; break; case "3": num = 3; break; case "4": num = 4; break; case "5": num = 5; break; case "6": num = 6; break; case "7": num = 7; break; case "8": num = 8; break; case "9": num = 9; break; case "A": case "a": num = 10; break; case "B": case "b": num = 11; break; case "C": case "c": num = 12; break; case "D": case "d": num = 13; break; case "E": case "e": num = 14; break; case "F": case "f": num = 15; break; default:return 0; break; } value += num * multiplier; multiplier *= 16; // correct for int overflow java expectation if (value > 2147483647) { value -= 4294967296; } } return value; }; // Load a file or URL into strings p.loadStrings = function loadStrings( url ){ return p.ajax( url ).split( "\n" ); }; // nf() should return an array when being called on an array, at the moment it only returns strings. -F1LT3R // This breaks the join() ref-test. The Processing.org documentation says String or String[]. p.nf = function (num, pad) { var str = "" + num; for (var i = pad - str.length; i > 0; i--) { str = "0" + str; } return str; }; p.nfp = function nfp(Value, pad, right) { var str = String(Value); if (arguments.length < 3) { //check if it's 2 arguments if (Value > 0) { while (str.length < pad) { str = "0" + str; } str = "+" + str; return str; } else { str = str.slice(1); //used to remove the '-' infront of the original number. while (str.length < pad) { str = "0" + str; } str = "-" + str; return str; } } else if (arguments.length === 3) { //check if it's 3 arguments var decimalPos = str.indexOf('.'), strL, strR; if (Value > 0) { strL = str.slice(0, decimalPos); //store #'s to left of decimal into strL strR = str.slice(decimalPos + 1, str.length); //store #'s to right of decimal into strR while (strL.length < pad) { //pad to left of decimal on positive #'s strL = "0" + strL; } strL = "+" + strL; while (strR.length < right) { //pad to right of decimal on positive #'s strR = strR + "0"; } return strL + "." + strR; } else { strL = str.slice(1, decimalPos); //store #'s to left of decimal into strL strR = str.slice(decimalPos + 1, str.length); //store #'s to right of decimal into strR while (strL.length < pad) { //pad to left of decimal on negative #'s strL = "0" + strL; } strL = "-" + strL; while (strR.length < right) { //pad to right of decimal on negative #'s strR = strR + "0"; } return strL + "." + strR; } } }; //////////////////////////////////////////////////////////////////////////// // String Functions //////////////////////////////////////////////////////////////////////////// // I have updated this to lint, we should check it still performs faster than the other option -F1LT3R p.matchAll = function matchAll(aString, aRegExp) { var i = 0, results = [], latest, regexp = new RegExp(aRegExp, "g"); latest = results[i] = regexp.exec(aString); while (latest) { i++; latest = results[i] = regexp.exec(aString); } return results.slice(0, i); }; String.prototype.replaceAll = function (re, replace) { return this.replace(new RegExp(re, "g"), replace); }; p.match = function (str, regexp) { return str.match(regexp); }; // Returns a line to lnPrinted() for user handling p.lnPrinted = function lnPrinted() {}; p.printed = function printed() {}; // Event to send output to user control function print()/println() p.println = function println() { // Not working on Safari :( find work around! if (arguments.callee.caller) { var Caller = arguments.callee.caller.name.toString(); if (arguments.length > 1) { p.ln = Caller !== "print" ? arguments : arguments[0]; } else { p.ln = arguments[0]; } //Returns a line to lnPrinted() for user error handling/debugging if (Caller === "print") { p.printed(arguments); } else { p.lnPrinted(); } } }; p.str = function str(aNumber) { return aNumber + ''; }; p.print = function print() { p.println(arguments[0]); }; p.char = function (key) { return key; }; //////////////////////////////////////////////////////////////////////////// // Math functions //////////////////////////////////////////////////////////////////////////// p.sq = function sq(aNumber) { return aNumber * aNumber; }; p.sqrt = function sqrt(aNumber) { return Math.sqrt(aNumber); }; p.int = function (aNumber) { return Math.floor(aNumber); }; p.min = function min(aNumber, aNumber2) { return Math.min(aNumber, aNumber2); }; p.max = function max(aNumber, aNumber2) { return Math.max(aNumber, aNumber2); }; p.floor = function floor(aNumber) { return Math.floor(aNumber); }; p.float = function (aNumber) { return parseFloat(aNumber); }; p.ceil = function ceil(aNumber) { return Math.ceil(aNumber); }; p.round = function round(aNumber) { return Math.round(aNumber); }; p.lerp = function lerp(value1, value2, amt) { return ((value2 - value1) * amt) + value1; }; p.abs = function abs(aNumber) { return Math.abs(aNumber); }; p.cos = function cos(aNumber) { return Math.cos(aNumber); }; p.sin = function sin(aNumber) { return Math.sin(aNumber); }; p.pow = function pow(aNumber, aExponent) { return Math.pow(aNumber, aExponent); }; p.sqrt = function sqrt(aNumber) { return Math.sqrt(aNumber); }; p.tan = function tan(aNumber) { return Math.tan(aNumber); }; p.atan = function atan(aNumber) { return Math.atan(aNumber); }; p.atan2 = function atan2(aNumber, aNumber2) { return Math.atan2(aNumber, aNumber2); }; p.radians = function radians(aAngle) { return (aAngle / 180) * p.PI; }; p.log = function log(aNumber) { return Math.log(aNumber); }; p.exp = function exp(aNumber) { return Math.exp(aNumber); }; p.asin = function asin(aNumber) { return Math.asin(aNumber); }; p.acos = function acos(aNumber) { return Math.acos(aNumber); }; p.boolean = function (val) { var ret = false; if (val && typeof val === 'number' && val !== 0) { ret = true; } else if (val && typeof val === 'boolean' && val === true) { ret = true; } else if (val && typeof val === 'string' && val.toLowerCase() === 'true') { ret = true; } else if (val && typeof val === 'object' && val.constructor === Array) { ret = new Array(val.length); for (var i = 0; i < val.length; i++) { ret[i] = p.boolean(val[i]); } } return ret; }; p.dist = function dist(x1, y1, x2, y2) { return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); }; p.map = function map(value, istart, istop, ostart, ostop) { return ostart + (ostop - ostart) * ((value - istart) / (istop - istart)); }; p.mag = function (a, b, c) { if (arguments.length === 2) { return Math.sqrt(a * a + b * b); } else if (arguments.length === 3) { return Math.sqrt(a * a + b * b + c * c); } }; p.Random = function () { var haveNextNextGaussian = false, nextNextGaussian; this.nextGaussian = function () { if (haveNextNextGaussian) { haveNextNextGaussian = false; return nextNextGaussian; } else { var v1, v2, s; do { v1 = 2 * p.random(1) - 1; // between -1.0 and 1.0 v2 = 2 * p.random(1) - 1; // between -1.0 and 1.0 s = v1 * v1 + v2 * v2; } while (s >= 1 || s === 0); var multiplier = Math.sqrt(-2 * Math.log(s) / s); nextNextGaussian = v2 * multiplier; haveNextNextGaussian = true; return v1 * multiplier; } }; }; //! This can't be right... right? p.byte = function (aNumber) { return aNumber || 0; }; p.norm = function norm(aNumber, low, high) { var range = high - low; return ((1 / range) * aNumber) - ((1 / range) * low); }; p.random = function random(aMin, aMax) { return arguments.length === 2 ? aMin + (Math.random() * (aMax - aMin)) : Math.random() * aMin; }; var noiseGen = function noiseGen(x, y) { var n = x + y * 57; n = (n << 13) ^ n; return Math.abs(1.0 - (((n * ((n * n * 15731) + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0)); }; var smoothedNoise = function smoothedNoise(x, y) { var corners = (noiseGen(x - 1, y - 1) + noiseGen(x + 1, y - 1) + noiseGen(x - 1, y + 1) + noiseGen(x + 1, y + 1)) / 16, sides = (noiseGen(x - 1, y) + noiseGen(x + 1, y) + noiseGen(x, y - 1) + noiseGen(x, y + 1)) / 8, center = noiseGen(x, y) / 4; return corners + sides + center; }; var interpolate = function interpolate(a, b, x) { var ft = x * p.PI; var f = (1 - Math.cos(ft)) * 0.5; return a * (1 - f) + b * f; }; var interpolatedNoise = function interpolatedNoise(x, y) { var integer_X = Math.floor(x); var fractional_X = x - integer_X; var integer_Y = Math.floor(y); var fractional_Y = y - integer_Y; var v1 = smoothedNoise(integer_X, integer_Y), v2 = smoothedNoise(integer_X + 1, integer_Y), v3 = smoothedNoise(integer_X, integer_Y + 1), v4 = smoothedNoise(integer_X + 1, integer_Y + 1); var i1 = interpolate(v1, v2, fractional_X), i2 = interpolate(v3, v4, fractional_X); return interpolate(i1, i2, fractional_Y); }; var perlinNoise_2D = function perlinNoise_2D(x, y) { var total = 0, p = 0.25, n = 3; for (var i = 0; i <= n; i++) { var frequency = Math.pow(2, i); var amplitude = Math.pow(p, i); total += interpolatedNoise(x * frequency, y * frequency) * amplitude; } return total; }; // Add Thomas Saunders 3D noiseGen code here.... var perlinNoise_3D = function perlinNoise_3D() { return 0; }; // From: http://freespace.virgin.net/hugo.elias/models/m_perlin.htm p.noise = function (x, y, z) { switch (arguments.length) { case 2: return perlinNoise_2D(x, y); case 3: return perlinNoise_3D(x, y, z); case 1: return perlinNoise_2D(x, x); } }; p.constrain = function constrain(aNumber, aMin, aMax) { return Math.min(Math.max(aNumber, aMin), aMax); }; p.degrees = function degrees(aAngle) { aAngle = (aAngle * 180) / p.PI; if (aAngle < 0) { aAngle = 360 + aAngle; } return aAngle; }; function PerlinNoise_2D( x, y ){ var total = 0, p = 0.25, n = 3; for( var i = 0; i <= n; i++ ){ var frequency = Math.pow( 2, i ); var amplitude = Math.pow( p, i ); total += InterpolatedNoise( x * frequency, y * frequency ) * amplitude; } return total; } function Interpolate( a, b, x ){ var ft = x * p.PI; var f = (1 - Math.cos( ft ) ) * .5; return a * ( 1 - f ) + b * f; } p.constrain = function constrain( aNumber, aMin, aMax ){ return Math.min( Math.max( aNumber, aMin ), aMax ); }; p.degrees = function degrees( aAngle ){ aAngle = ( aAngle * 180 ) / p.PI; if (aAngle < 0) {aAngle = 360 + aAngle} return aAngle; }; // Changes the size of the Canvas ( this resets context properties like 'lineCap', etc. p.size = function size( aWidth, aHeight ){ p.context = new VectorLayer(aWidth, aHeight); // default white on black p.background(0,0,0,0); p.context.set_color(255); p.context.start(); add_layer(p.context); p.width = aWidth; p.height = aHeight; srand(); var props = { fillStyle : p.context.fillStyle, strokeStyle : p.context.strokeStyle, lineCap : p.context.lineCap } // More to be added... // curElement.width = p.width = aWidth; // curElement.height = p.height = aHeight; // for( var i in props ){ // p.context[ i ] = props[ i ] // }; }; // PVector instantiation p.PVector = function PVector(){ return new vectorOps( arguments ) }; // PVector method translation p.PVector.add = PVectorAdd; p.PVector.sub = PVectorSub; p.PVector.mult = PVectorMult; p.PVector.div = PVectorDiv; p.PVector.dist = PVectorDist; p.PVector.angleBetween = PVectorAngle; // PVector methods function PVectorAdd(){ var a = arguments; return p.PVector( a[0].x + a[1].x, a[0].y + a[1].y, a[0].z + a[1].z ); } function PVectorSub(){ var a = arguments; return p.PVector( a[0].x - a[1].x, a[0].y - a[1].y,a[0].z - a[1].z ); } function PVectorMult(){ if( typeof arguments[1] == 'number' ){ var a = arguments; return p.PVector( a[0].x * a[1], a[0].y * a[1], a[0].z * a[1] ); }else if( typeof arguments[1] == 'object' ){ var a = arguments; return p.PVector( a[0].x * a[1].x, a[0].y * a[1].y, a[0].z * a[1].z ); } } function PVectorDiv(){ if( typeof arguments[1] == 'number' ){ var a = arguments; return p.PVector( a[0].x / a[1], a[0].y / a[1], a[0].z / a[1] ); } else if ( typeof (arguments[1]) == 'object' ){ var a = arguments; return p.PVector( a[0].x / a[1].x, a[0].y / a[1].y, a[0].z / a[1].z ); } } function PVectorDist(){ var v1 = new p.PVector(); var v2 = new p.PVector(); v1 = arguments[0]; v2 = arguments[1]; return v1.dist(v2); } function PVectorAngle(v1, v2){ return Math.acos( v1.dot(v2) / (v1.mag()*v2.mag()) ); } // Common vector operations for PVector function vectorOps(){ arguments = arguments[0]; this.x = arguments[ 0 ] || 0; this.y = arguments[ 1 ] || 0; this.z = arguments[ 2 ] || 0; this.set = function(){ if (arguments.length == 1){ var vArr = arguments[0]; this.set(arguments[0].x || vArr[0], arguments[0].y || vArr[1], arguments[0].z || vArr[2]); }else{ this.x = arguments[0]; this.y = arguments[1]; this.z = arguments[2]; }; }; this.get = function get(){ return p.PVector( this.x, this.y, this.z ) }; this.mag = function mag(){ return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ) }; this.add = function(){ if( arguments.length == 3 ){ this.x += arguments[0]; this.y += arguments[1]; this.z += arguments[2]; }else if( arguments.length == 1 ){ this.x += arguments[0].x; this.y += arguments[0].y; this.z += arguments[0].z; }; }; this.sub = function(){ if( arguments.length == 3 ){ this.x -= arguments[0]; this.y -= arguments[1]; this.z -= arguments[2]; }else if( arguments.length == 1 ){ this.x -= arguments[0].x; this.y -= arguments[0].y; this.z -= arguments[0].z; }; }; this.mult = function(){ if( typeof arguments[0] == 'number' ){ this.x *= arguments[0]; this.y *= arguments[0]; this.z *= arguments[0]; }else if( typeof arguments[0] == 'object' ){ this.x *= arguments[0].x; this.y *= arguments[0].y; this.z *= arguments[0].z; }; }; this.div = function(){ if( typeof arguments[0] == 'number' ){ this.x /= arguments[0]; this.y /= arguments[0]; this.z /= arguments[0]; }else if( typeof arguments[0] == 'object' ){ this.x /= arguments[0].x; this.y /= arguments[0].y; this.z /= arguments[0].z; }; }; this.dist = function(){ var v = new p.PVector(); v = arguments[0]; var dx = this.x - v.x; var dy = this.y - v.y; var dz = this.z - v.z; return Math.sqrt( dx*dx + dy*dy + dz*dz ); }; this.dot = function dot(){ var num; if( arguments.length == 3 ){ num = this.x * arguments[0] + this.y * arguments[1] + this.z * arguments[2]; }else if( arguments.length == 2 ){ var v1 = new p.PVector(); var v2 = new p.PVector(); v1 = arguments[0]; v2 = arguments[1]; num = v1.dot(v2); }else if( arguments.length == 1 ){ var v = new p.PVector(); v = arguments[0]; num = this.x * v.x + this.y * v.y + this.z * v.z; }; return num; }; this.cross = function cross(){ var crossX, crossY, crossZ; var v = new p.PVector(); // Will implement at later date - aSydiK :: What do you mean? - F1LT3R v = arguments[0]; crossX = this.y * v.z - v.y * this.z; crossY = this.z * v.x - v.z * this.x; crossZ = this.x * v.y - v.x * this.y; return p.PVector( crossX, crossY, crossZ ); }; this.normalize = function normalize(){ var m = this.mag(); console.log( m ); if( m > 0 ){ this.div( m ) }; }; this.limit = function limit( high ){ if( this.mag() > high ){ this.normalize(); this.mult( high ); }; }; this.angleBetween = function(){ PVectorAngle.call( this, arguments ); }; this.array = function array(){ var vArray = new Array( 3 ); vArray[0] = this.x; vArray[1] = this.y; vArray[2] = this.z; return vArray; }; } // End of PVector operations //////////////////////////////////////////////////////////////////////////// // Style functions //////////////////////////////////////////////////////////////////////////// p.noStroke = function noStroke() { doStroke = false; }; p.noFill = function noFill() { doFill = false; }; p.smooth = function smooth() {}; p.noSmooth = function noSmooth() {}; p.fill = function(){ doFill = true; p.context.set_color.apply(p.context, arguments); }; p.stroke = function() { doStroke = true; p.context.set_color.apply(p.context, arguments); } // echo ("STROKE args: " + arguments); // doStroke = true; // doStrokeArgs = arguments // // our own freej color function -jrml // // p.context.color.apply(p.context, arguments); // }; p.strokeWeight = function strokeWeight( w ){ p.context.lineWidth = w; }; //////////////////////////////////////////////////////////////////////////// // Vector drawing functions //////////////////////////////////////////////////////////////////////////// p.Point = function Point( x, y ){ this.x = x; this.y = y; this.copy = function(){ return new Point( x, y ); } }; p.point = function point( x, y ){ var oldFill = p.context.fillStyle; p.context.fillStyle = p.context.strokeStyle; p.context.fillRect( Math.round( x ), Math.round( y ), 1, 1 ); p.context.fillStyle = oldFill; }; p.beginShape = function beginShape( type ){ curShape = type; curShapeCount = 0; curvePoints = []; }; p.endShape = function endShape( close ){ if( curShapeCount != 0 ){ if( close || doFill ){ p.context.lineTo( firstX, firstY ); } if( doFill ){ p.context.fill(); } if( doStroke ){ p.context.stroke(); } p.context.closePath(); curShapeCount = 0; pathOpen = false; } if( pathOpen ){ if ( doFill ){ p.context.fill(); } if ( doStroke ){ p.context.stroke(); } p.context.closePath(); curShapeCount = 0; pathOpen = false; } }; p.vertex = function vertex( x, y, x2, y2, x3, y3 ){ if( curShapeCount == 0 && curShape != p.POINTS ){ pathOpen = true; p.context.beginPath(); p.context.moveTo( x, y ); firstX = x; firstY = y; }else{ if( curShape == p.POINTS ){ p.point( x, y ); }else if( arguments.length == 2 ){ if( curShape != p.QUAD_STRIP || curShapeCount != 2 ){ p.context.lineTo( x, y ); } if( curShape == p.TRIANGLE_STRIP ){ if( curShapeCount == 2 ){ // finish shape p.endShape( p.CLOSE ); pathOpen = true; p.context.beginPath(); // redraw last line to start next shape p.context.moveTo( prevX, prevY ); p.context.lineTo( x, y ); curShapeCount = 1; } firstX = prevX; firstY = prevY; } if( curShape == p.TRIANGLE_FAN && curShapeCount == 2 ){ // finish shape p.endShape( p.CLOSE) ; pathOpen = true; p.context.beginPath(); // redraw last line to start next shape p.context.moveTo( firstX, firstY ); p.context.lineTo( x, y ); curShapeCount = 1; } if( curShape == p.QUAD_STRIP && curShapeCount == 3 ){ // finish shape p.context.lineTo( prevX, prevY ); p.endShape(p.CLOSE); pathOpen = true; p.context.beginPath(); // redraw lines to start next shape p.context.moveTo( prevX, prevY ); p.context.lineTo( x, y ); curShapeCount = 1; } if( curShape == p.QUAD_STRIP ){ firstX = secondX; firstY = secondY; secondX = prevX; secondY = prevY; } }else if( arguments.length == 4 ){ if( curShapeCount > 1 ){ p.context.moveTo( prevX, prevY ); p.context.quadraticCurveTo( firstX, firstY, x, y ); curShapeCount = 1; } }else if( arguments.length == 6 ){ p.context.bezierCurveTo( x, y, x2, y2, x3, y3 ); } } prevX = x; prevY = y; curShapeCount ++; if( curShape == p.LINES && curShapeCount == 2 || ( curShape == p.TRIANGLES ) && curShapeCount == 3 || ( curShape == p.QUADS ) && curShapeCount == 4 ){ p.endShape( p.CLOSE ); } }; p.curveVertex = function( x, y, x2, y2 ){ if( curvePoints.length < 3 ){ curvePoints.push( [ x, y ] ); }else{ var b = [], s = 1 - curTightness; /* * Matrix to convert from Catmull-Rom to cubic Bezier * where t = curTightness * |0 1 0 0 | * |(t-1)/6 1 (1-t)/6 0 | * |0 (1-t)/6 1 (t-1)/6 | * |0 0 0 0 | */ curvePoints.push( [ x, y ] ); b[ 0 ] = [ curvePoints[ 1 ][ 0 ], curvePoints[ 1 ][ 1 ] ]; b[ 1 ] = [ curvePoints[ 1 ][ 0 ] + ( s * curvePoints[ 2 ][ 0 ] - s * curvePoints[ 0 ][ 0 ] ) / 6, curvePoints[ 1 ][ 1 ] + ( s * curvePoints[ 2 ][ 1 ] - s * curvePoints[ 0 ][ 1 ] ) / 6 ]; b[ 2 ] = [ curvePoints[ 2 ][ 0 ] + ( s * curvePoints[ 1 ][ 0 ] - s * curvePoints[ 3 ][ 0 ] ) / 6, curvePoints[ 2 ][ 1 ] + ( s * curvePoints[ 1 ][ 1 ] - s * curvePoints[ 3 ][ 1 ] ) / 6 ]; b[ 3 ] = [ curvePoints[ 2 ][ 0 ], curvePoints[ 2 ][ 1 ] ]; if( !pathOpen ){ p.vertex( b[ 0 ][ 0 ], b[ 0 ][ 1 ] ); }else{ curShapeCount = 1; } p.vertex( b[ 1 ][ 0 ], b[ 1 ][ 1 ], b[ 2 ][ 0 ], b[ 2 ][ 1 ], b[ 3 ][ 0 ], b[ 3 ][ 1 ] ); curvePoints.shift(); } }; p.curveTightness = function( tightness ){ curTightness = tightness; }; p.bezierVertex = p.vertex; p.rectMode = function rectMode( aRectMode ){ curRectMode = aRectMode; }; p.imageMode = function (){}; p.ellipseMode = function ellipseMode( aEllipseMode ) { curEllipseMode = aEllipseMode; }; p.arc = function arc( x, y, width, height, start, stop ){ if( width <= 0 ){ return; } if( curEllipseMode == p.CORNER ){ x += width / 2; y += height / 2; } p.context.moveTo( x, y ); p.context.beginPath(); p.context.arc( x, y, curEllipseMode == p.CENTER_RADIUS ? width : width/2, start, stop, false ); if( doStroke ){ p.context.stroke(); } p.context.lineTo( x, y ); if( doFill ){ p.context.fill(); } p.context.closePath(); }; // QUAAA optimize by implementing these iterations in C++ p.line = function line( x1, y1, x2, y2 ){ p.context.lineCap = "round"; p.context.beginPath(); p.context.moveTo( x1, y1 ); p.context.lineTo( x2, y2 ); p.context.stroke(); p.context.closePath(); }; p.bezier = function bezier( x1, y1, x2, y2, x3, y3, x4, y4 ){ p.context.lineCap = "butt"; p.context.beginPath(); p.context.moveTo( x1, y1 ); p.context.bezierCurveTo( x2, y2, x3, y3, x4, y4 ); p.context.stroke(); p.context.closePath(); }; p.triangle = function triangle( x1, y1, x2, y2, x3, y3 ){ p.beginShape(); p.vertex( x1, y1 ); p.vertex( x2, y2 ); p.vertex( x3, y3 ); p.endShape(); }; p.quad = function quad( x1, y1, x2, y2, x3, y3, x4, y4 ){ p.context.lineCap = "square"; p.beginShape(); p.vertex( x1, y1 ); p.vertex( x2, y2 ); p.vertex( x3, y3 ); p.vertex( x4, y4 ); p.endShape(); }; p.rect = function rect( x, y, width, height ){ if( !( width + height ) ){ return; } p.context.beginPath(); var offsetStart = 0; var offsetEnd = 0; if( curRectMode == p.CORNERS ){ width -= x; height -= y; } if( curRectMode == p.RADIUS ){ width *= 2; height *= 2; } if( curRectMode == p.CENTER || curRectMode == p.RADIUS ){ x -= width / 2; y -= height / 2; } p.context.rect( Math.round( x ) - offsetStart, Math.round( y ) - offsetStart, Math.round( width ) + offsetEnd, Math.round( height ) + offsetEnd ); if( doFill ){ p.context.fill(); } if( doStroke ){ p.context.stroke() }; p.context.closePath(); }; p.ellipse = function ellipse( x, y, width, height ){ x = x || 0; y = y || 0; if( width <= 0 && height <= 0 ){ return; } p.context.beginPath(); if( curEllipseMode == p.RADIUS ){ width *= 2; height *= 2; } var offsetStart = 0; // Shortcut for drawing a circle if( width == height ){ p.context.arc( x - offsetStart, y - offsetStart, width / 2, 0, p.TWO_PI, false ); }else{ var w = width/2, h = height/2, C = 0.5522847498307933; var c_x = C * w, c_y = C * h; //! Do we still need this? I hope the Canvas arc() more capable by now? p.context.moveTo( x + w, y ); p.context.bezierCurveTo( x+w , y-c_y , x+c_x , y-h , x , y-h ); p.context.bezierCurveTo( x-c_x , y-h , x-w , y-c_y , x-w , y ); p.context.bezierCurveTo( x-w , y+c_y , x-c_x , y+h, x, y+h ); p.context.bezierCurveTo( x+c_x , y+h , x+w , y+c_y , x+w , y ); } if( doFill ){ p.context.fill(); } if( doStroke ){ p.context.stroke(); } p.context.closePath(); }; //////////////////////////////////////////////////////////////////////////// // Raster drawing functions //////////////////////////////////////////////////////////////////////////// p.save = function save( file ){}; // Loads an image for display. Type is unused. Callback is fired on load. p.loadImage = function loadImage( file, type, callback ){ var img = document.createElement( 'img' ); img.src = file; img.onload = function(){ var h = this.height, w = this.width; var canvas = document.createElement( "canvas" ); canvas.width = w; canvas.height = h; var context = canvas.getContext( "2d" ); context.drawImage( this, 0, 0 ); this.data = buildImageObject( context.getImageData( 0, 0, w, h ) ); this.data.img = img; callback?callback():0; } return img; }; // Gets a single pixel or block of pixels from the current Canvas Context // p.get = function get( x, y ){ // if( !arguments.length ){ // var c = p.createGraphics( p.width, p.height ); // c.image( p.context, 0, 0 ); // return c; // } // if( !getLoaded ){ // getLoaded = buildImageObject( p.context.getImageData( 0, 0, p.width, p.height ) ); // } // return getLoaded.get( x, y ); // }; // // Creates a new Processing instance and passes it back for... processing // p.createGraphics = function createGraphics( w, h ){ // var canvas = document.createElement( "canvas" ); // var ret = buildProcessing( canvas ); // ret.size( w, h ); // ret.canvas = canvas; // return ret; // }; // Paints a pixel array into the canvas p.set = function set( x, y, obj ){ if( obj && obj.img ){ p.image( obj, x, y ); }else{ var oldFill = p.context.fillStyle, color = obj; p.context.fillStyle = color; p.context.fillRect( Math.round( x ), Math.round( y ), 1, 1 ); p.context.fillStyle = oldFill; } }; // Gets a 1-Dimensional pixel array from Canvas p.loadPixels = function(){ p.pixels = buildImageObject( p.context.getImageData(0, 0, p.width, p.height) ).pixels; }; // Draws a 1-Dimensional pixel array to Canvas p.updatePixels = function() { var colors = /(\d+),(\d+),(\d+),(\d+)/, pixels = {}; pixels.width = p.width; pixels.height = p.height; pixels.data = []; if( p.context.createImageData ){ pixels = p.context.createImageData( p.width, p.height ); } var data = pixels.data, pos = 0; for( var i = 0, l = p.pixels.length; i < l; i++ ){ var c = ( p.pixels[i] || "rgba(0,0,0,1)" ).match( colors ); data[ pos + 0 ] = parseInt( c[ 1 ] ); data[ pos + 1 ] = parseInt( c[ 2 ] ); data[ pos + 2 ] = parseInt( c[ 3 ] ); data[ pos + 3 ] = parseFloat( c[ 4 ] ) * 255; pos += 4; } p.context.putImageData( pixels, 0, 0 ); }; // Draw an image or a color to the background p.background = function background( img ) { if( arguments.length ){ if( img.data && img.data.img ){ curBackground = img.data; }else{ p.context.push_color(); p.context.set_color.apply(p.context, arguments); // curBackground = p.color.apply( this, arguments ); } } if( curBackground.img ){ p.image( img, 0, 0 ); }else{ // var oldFill = p.context.fillStyle; // p.context.fillStyle = curBackground + ""; // p.context.set_color(0); // echo("background fill"); p.context.fillRect( 0, 0, p.width, p.height ); p.context.pop_color(); } }; p.AniSprite = function( prefix, frames ){ this.images = []; this.pos = 0; for( var i = 0; i < frames; i++ ){ this.images.push( prefix + p.nf( i, ( "" + frames ).length ) + ".gif" ); } this.display = function( x, y ){ p.image_old( this.images[ this.pos ], x, y ); if( ++this.pos >= frames ){ this.pos = 0; } }; this.getWidth = function(){ return getImage_old( this.images[ 0 ] ).width; }; this.getHeight = function(){ return getImage_old( this.images[ 0 ] ).height; }; }; function buildImageObject( obj ){ var pixels = obj.data; var data = p.createImage( obj.width, obj.height ); if( data.__defineGetter__ && data.__lookupGetter__ && !data.__lookupGetter__( "pixels" ) ){ var pixelsDone; data.__defineGetter__( "pixels", function(){ if( pixelsDone ){ return pixelsDone; } pixelsDone = []; for( var i = 0; i < pixels.length; i += 4 ){ pixelsDone.push( p.color( pixels[ i ], pixels[ i + 1 ], pixels[ i + 2 ], pixels[ i + 3 ]) ); } return pixelsDone; }); }else{ data.pixels = []; for ( var i = 0; i < pixels.length; i += 4 ){ data.pixels.push( p.color( pixels[ i ], pixels[ i + 1 ], pixels[ i + 2 ], pixels[ i + 3 ] )); } } return data; } p.createImage = function createImage( w, h, mode ){ var data = {}; data.width = w; data.height = h; data.data = []; if( p.context.createImageData ) { data = p.context.createImageData( w, h ); } data.pixels = new Array( w * h ); data.get = function( x, y ){ return this.pixels[ w * y + x ]; }; data._mask = null; data.mask = function( img ){ this._mask = img; }; data.loadPixels = function(){}; data.updatePixels = function(){}; return data; }; function getImage( img ){ if( typeof img == "string" ){ return document.getElementById( img ); } if( img.img ){ return img.img; }else if( img.getContext || img.canvas ){ img.pixels = img.getContext( '2d' ).createImageData( img.width, img.height ); } for( var i = 0, l = img.pixels.length; i < l; i++ ){ var pos = i * 4; var c = ( img.pixels[ i ] || "rgba(0,0,0,1)" ).slice( 5, - 1 ).split( "," ); img.data[ pos + 0 ] = parseInt( c[ 0 ] ); img.data[ pos + 1 ] = parseInt( c[ 1 ] ); img.data[ pos + 2 ] = parseInt( c[ 2 ] ); img.data[ pos + 3 ] = parseFloat( c[ 3 ] ) * 100; } var canvas = document.createElement( "canvas" ); canvas.width = img.width; canvas.height = img.height; var context = canvas.getContext( "2d" ); context.putImageData( img.pixels, 0, 0 ); img.canvas = canvas; return img; } // Depreciating "getImage_old" from PJS - currently here to support AniSprite function getImage_old( img ){ if( typeof img == "string" ){ return document.getElementById( img ); } if( img.img || img.canvas ){ return img.img || img.canvas; } for( var i = 0, l = img.pixels.length; i < l; i++ ){ var pos = i * 4; var c = ( img.pixels[ i ] || "rgba(0,0,0,1)" ).slice( 5, - 1 ).split( "," ); img.data[ pos + 0 ] = parseInt( c[ 0 ] ); img.data[ pos + 1 ] = parseInt( c[ 1 ] ); img.data[ pos + 2 ] = parseInt( c[ 2 ] ); img.data[ pos + 3 ] = parseFloat( c[ 3 ] ) * 100; } var canvas = document.createElement( "canvas" ); canvas.width = img.width; canvas.height = img.height; var context = canvas.getContext( "2d" ); context.putImageData( img, 0, 0 ); img.canvas = canvas; return canvas; } // Depreciating "getImage_old" from PJS - currently here to support AniSprite p.image_old=function image_old(img,x,y,w,h){ x = x || 0; y = y || 0; var obj = getImage( img ); if( curTint >= 0 ){ var oldAlpha = p.context.globalAlpha; p.context.globalAlpha = curTint / opacityRange; } if( arguments.length == 3 ){ p.context.drawImage( obj, x, y ); }else{ p.context.drawImage( obj, x, y, w, h ); } if( curTint >= 0 ){ p.context.globalAlpha = oldAlpha; } if( img._mask ){ var oldComposite = p.context.globalCompositeOperation; p.context.globalCompositeOperation = "darker"; p.image( img._mask, x, y ); p.context.globalCompositeOperation = oldComposite; } }; // Draws an image to the Canvas p.image = function image( img, x, y, w, h ){ if( img.data || img.canvas ){ x = x || 0; y = y || 0; var obj = getImage( img.data || img.canvas ); if( curTint >= 0 ){ var oldAlpha = p.context.globalAlpha; p.context.globalAlpha = curTint / opacityRange; } if( arguments.length == 3 ){ p.context.drawImage( obj, x, y ); }else{ p.context.drawImage( obj, x, y, w, h ); } if( curTint >= 0 ){ p.context.globalAlpha = oldAlpha; } if( img._mask ){ var oldComposite = p.context.globalCompositeOperation; p.context.globalCompositeOperation = "darker"; p.image( img._mask, x, y ); p.context.globalCompositeOperation = oldComposite; } } if( typeof img == 'string' ){ } }; // Clears a rectangle in the Canvas element or the whole Canvas p.clear = function clear ( x, y, width, height ) { if( arguments.length == 0 ){ p.context.clearRect( 0, 0, p.width, p.height ); }else{ p.context.clearRect( x, y, width, height ); } } p.tint = function tint( rgb, a ){ curTint = a; }; //////////////////////////////////////////////////////////////////////////// // Font handling //////////////////////////////////////////////////////////////////////////// // Loads a font from an SVG or Canvas API p.loadFont = function loadFont( name ){ if( name.indexOf( ".svg" ) == - 1 ){ return { name: name, width: function( str ){ if( p.context.mozMeasureText ){ return p.context.mozMeasureText( typeof str == "number" ? String.fromCharCode( str ) : str ) / curTextSize; }else{ return 0; } } }; }else{ // If the font is a glyph, calculate by SVG table var font = p.loadGlyphs( name ); return { name : name, glyph : true, units_per_em : font.units_per_em, horiz_adv_x : 1 / font.units_per_em * font.horiz_adv_x, ascent : font.ascent, descent : font.descent, width : function( str ){ var width = 0; var len = str.length; for( var i = 0; i < len; i++ ){ try{ width += parseFloat( p.glyphLook( p.glyphTable[ name ], str[ i ] ).horiz_adv_x ); } catch( e ){ ; } } return width / p.glyphTable[ name ].units_per_em; } } } }; // Sets a 'current font' for use p.textFont = function textFont( name, size ){ curTextFont = name; p.textSize( size ); }; // Sets the font size p.textSize = function textSize( size ){ //! Was this meant to return textSize value if no arguments were passed? if( size ){ curTextSize = size; } }; p.textAlign = function textAlign(){}; // A lookup table for characters that can not be referenced by Object p.glyphLook = function glyphLook( font, chr ){ try{ switch( chr ){ case "1" : return font[ "one" ]; break; case "2" : return font[ "two" ]; break; case "3" : return font[ "three" ]; break; case "4" : return font[ "four" ]; break; case "5" : return font[ "five" ]; break; case "6" : return font[ "six" ]; break; case "7" : return font[ "seven" ]; break; case "8" : return font[ "eight" ]; break; case "9" : return font[ "nine" ]; break; case "0" : return font[ "zero" ]; break; case " " : return font[ "space" ]; break; case "$" : return font[ "dollar" ]; break; case "!" : return font[ "exclam" ]; break; case '"' : return font[ "quotedbl" ]; break; case "#" : return font[ "numbersign" ]; break; case "%" : return font[ "percent" ]; break; case "&" : return font[ "ampersand" ]; break; case "'" : return font[ "quotesingle" ]; break; case "(" : return font[ "parenleft" ]; break; case ")" : return font[ "parenright" ]; break; case "*" : return font[ "asterisk" ]; break; case "+" : return font[ "plus" ]; break; case "," : return font[ "comma" ]; break; case "-" : return font[ "hyphen" ]; break; case "." : return font[ "period" ]; break; case "/" : return font[ "slash" ]; break; case "_" : return font[ "underscore" ]; break; case ":" : return font[ "colon" ]; break; case ";" : return font[ "semicolon" ]; break; case "<" : return font[ "less" ]; break; case "=" : return font[ "equal" ]; break; case ">" : return font[ "greater" ]; break; case "?" : return font[ "question" ]; break; case "@" : return font[ "at" ]; break; case "[" : return font[ "bracketleft" ]; break; case "\\" : return font[ "backslash" ]; break; case "]" : return font[ "bracketright" ]; break; case "^" : return font[ "asciicircum" ]; break; case "`" : return font[ "grave" ]; break; case "{" : return font[ "braceleft" ]; break; case "|" : return font[ "bar" ]; break; case "}" : return font[ "braceright" ]; break; case "~" : return font[ "asciitilde" ]; break; // If the character is not 'special', access it by object reference default : return font[ chr ]; break; } }catch( e ){ ; } } // Print some text to the Canvas p.text = function text( str, x, y ){ // If the font is a standard Canvas font... if( !curTextFont.glyph ){ if( str && p.context.mozDrawText ){ p.context.save(); p.context.mozTextStyle = curTextSize + "px " + curTextFont.name; p.context.translate( x, y ); p.context.mozDrawText( typeof str == "number" ? String.fromCharCode( str ) : str ) ; p.context.restore(); } }else{ // If the font is a Batik SVG font... var font = p.glyphTable[ curTextFont.name ]; p.context.save(); p.context.translate( x, y + curTextSize ); var upem = font[ "units_per_em" ], newScale = 1 / upem * curTextSize; p.context.scale( newScale, newScale ); var len = str.length; for(var i = 0; i < len; i++ ){ // Test character against glyph table try{ p.glyphLook( font, str[ i ] ).draw(); } catch( e ){ ; } } p.context.restore(); } }; // Load Batik SVG Fonts and parse to pre-def objects for quick rendering p.loadGlyphs = function loadGlyph( url ){ // Load and parse Batik SVG font as XML into a Processing Glyph object var loadXML = function loadXML(){ try{ var xmlDoc = new ActiveXObject( "Microsoft.XMLDOM" ); } catch( e ){ try{ xmlDoc=document.implementation.createDocument( "", "", null ); } catch( e ){ p.println( e.message ); return; } }; try{ xmlDoc.async = false; xmlDoc.load( url ); parse( xmlDoc.getElementsByTagName( "svg" )[ 0 ] ); } catch( e ){ // Google Chrome, Safari etc. try{ p.println( e.message ); var xmlhttp = new window.XMLHttpRequest(); xmlhttp.open( "GET", url, false ); xmlhttp.send( null ); parse( xmlhttp.responseXML.documentElement ); } catch( e ){ ; } } }; // Return arrays of SVG commands and coords var regex = function regex( needle, hay ){ var regexp = new RegExp( needle, "g" ), results = [], i = 0; while( results[ i ] = regexp.exec( hay ) ){ i++; } return results; } // Parse SVG font-file into block of Canvas commands var parse = function parse( svg ){ // Store font attributes var font = svg.getElementsByTagName( "font" ); p.glyphTable[ url ][ "horiz_adv_x" ] = font[ 0 ].getAttribute( "horiz-adv-x" ); var font_face = svg.getElementsByTagName( "font-face" )[ 0 ]; p.glyphTable[ url ][ "units_per_em" ] = parseFloat( font_face.getAttribute( "units-per-em") ); p.glyphTable[ url ][ "ascent" ] = parseFloat( font_face.getAttribute( "ascent" ) ); p.glyphTable[ url ][ "descent" ] = parseFloat( font_face.getAttribute( "descent" ) ); var getXY = "[0-9\-]+", glyph = svg.getElementsByTagName( "glyph" ), len = glyph.length; // Loop through each glyph in the SVG for( var i = 0; i < len; i++ ){ // Store attributes for this glyph var unicode = glyph[ i ].getAttribute( "unicode" ); var name = glyph[ i ].getAttribute( "glyph-name" ); var horiz_adv_x = glyph[ i ].getAttribute( "horiz-adv-x" ); if( horiz_adv_x == null ){ var horiz_adv_x = p.glyphTable[ url ][ 'horiz_adv_x' ]; } var buildPath = function buildPath( d ){ var c = regex( "[A-Za-z][0-9\- ]+|Z", d ); // Begin storing path object var path = "var path={draw:function(){p.context.beginPath();p.context.save();"; var x = 0, y = 0, cx = 0, cy = 0, nx = 0, ny = 0, d = 0, a = 0, lastCom = "", lenC = c.length - 1; // Loop through SVG commands translating to canvas eqivs functions in path object for( var j = 0; j < lenC; j++ ){ var com = c[ j ][ 0 ], xy = regex( getXY, com ); switch( com[ 0 ] ){ case "M": //p.context.moveTo(x,-y); x = parseFloat( xy[ 0 ][ 0 ] ); y = parseFloat( xy[ 1 ][ 0 ] ); //! Brackets needed on (-y)? path += "p.context.moveTo("+ x +","+ (-y) +");"; break; case "L": //p.context.lineTo(x,-y); x = parseFloat( xy[ 0 ][ 0 ] ); y = parseFloat( xy[ 1 ][ 0 ] ); path += "p.context.lineTo("+ x +","+ (-y) +");"; break; case "H"://p.context.lineTo(x,-y) x = parseFloat( xy[ 0 ][ 0 ] ); path += "p.context.lineTo("+ x +","+ (-y) +");"; break; case "V"://p.context.lineTo(x,-y); y = parseFloat( xy[ 0 ][ 0 ] ); path += "p.context.lineTo("+ x +","+ (-y) +");"; break; case "T"://p.context.quadraticCurveTo(cx,-cy,nx,-ny); nx = parseFloat( xy[ 0 ][ 0 ] ); ny = parseFloat( xy[ 1 ][ 0 ] ); if( lastCom == "Q" || lastCom == "T" ){ d = Math.sqrt( Math.pow( x - cx, 2 ) + Math.pow( cy - y, 2 ) ); a = Math.PI+Math.atan2( cx - x, cy - y ); cx = x + ( Math.sin( a ) * ( d ) ); cy = y + ( Math.cos( a ) * ( d ) ); }else{ cx = x; cy = y; } path += "p.context.quadraticCurveTo("+ cx +","+ (-cy) +","+ nx +","+ (-ny) +");"; x = nx; y = ny; break; case "Q"://p.context.quadraticCurveTo(cx,-cy,nx,-ny); cx = parseFloat( xy[ 0 ][ 0 ] ); cy = parseFloat( xy[ 1 ][ 0 ] ); nx = parseFloat( xy[ 2 ][ 0 ] ); ny = parseFloat( xy[ 3 ][ 0 ] ); path += "p.context.quadraticCurveTo("+ cx +","+ (-cy) +","+ nx +","+ (-ny) +");"; x = nx; y = ny; break; case "Z"://p.context.closePath(); path += "p.context.closePath();"; break; } lastCom = com[ 0 ]; } path += "doStroke?p.context.stroke():0;"; path += "doFill?p.context.fill():0;"; path += "p.context.restore();"; path += "p.context.translate("+ horiz_adv_x +",0);"; path += "}}"; return path; } var d = glyph[ i ].getAttribute( "d" ); // Split path commands in glpyh if( d !== undefined ){ var path = buildPath( d ); eval( path ); // Store glyph data to table object p.glyphTable[ url ][ name ] = { name : name, unicode : unicode, horiz_adv_x : horiz_adv_x, draw : path.draw } } } // finished adding glyphs to table } // Create a new object in glyphTable to store this font p.glyphTable[ url ] = {}; // Begin loading the Batik SVG font... loadXML( url ); // Return the loaded font for attribute grabbing return p.glyphTable[ url ]; } //////////////////////////////////////////////////////////////////////////// // Class methods //////////////////////////////////////////////////////////////////////////// p.extendClass = function extendClass( obj, args, fn ){ if( arguments.length == 3 ){ fn.apply( obj, args ); }else{ args.call( obj ); } }; p.addMethod = function addMethod( object, name, fn ){ if( object[ name ] ){ var args = fn.length, oldfn = object[ name ]; object[ name ] = function(){ if( arguments.length == args ){ return fn.apply( this, arguments ); }else{ return oldfn.apply( this, arguments ); } }; }else{ object[ name ] = fn; } }; //////////////////////////////////////////////////////////////////////////// // Set up environment //////////////////////////////////////////////////////////////////////////// p.init = function init(code){ // p.stroke( 255 ); // p.fill( 255 ); // Canvas has trouble rendering single pixel stuff on whole-pixel // counts, so we slightly offset it (this is super lame). // p.context.translate( 0.5, 0.5 ); // luckily enough FreeJ is not-so-lame... // The fun bit! if( code ){ (function( Processing ){ with ( p ){ eval(parse(code, p)); } })( p ); } if( p.setup ){ inSetup = true; p.setup(); } inSetup = false; if( p.draw ){ if( !doLoop ){ p.redraw(); } else { p.loop(); } } ////////////////////////////////////////////////////////////////////////// // Event handling ////////////////////////////////////////////////////////////////////////// /* attach( curElement, "mousemove" , function(e){ var scrollX = window.scrollX != null ? window.scrollX : window.pageXOffset; var scrollY = window.scrollY != null ? window.scrollY : window.pageYOffset; p.pmouseX = p.mouseX; p.pmouseY = p.mouseY; p.mouseX = e.clientX - curElement.offsetLeft + scrollX; p.mouseY = e.clientY - curElement.offsetTop + scrollY; if( p.mouseMoved ){ p.mouseMoved(); } if( mousePressed && p.mouseDragged ){ p.mouseDragged(); } }); attach( curElement, "mouseout" , function( e ){ p.cursor("auto"); }); attach( curElement, "mousedown", function( e ){ mousePressed = true; switch(e.which){ case 1: p.mouseButton = p.LEFT; break; case 2: p.mouseButton = p.CENTER; break; case 3: p.mouseButton = p.RIGHT; break; } p.mouseDown = true; if( typeof p.mousePressed == "function" ){ p.mousePressed(); } else{ p.mousePressed = true; } }); attach( curElement, "mouseup", function( e ){ mousePressed = false; if( p.mouseClicked ){ p.mouseClicked(); } if( typeof p.mousePressed != "function" ){ p.mousePressed = false; } if( p.mouseReleased ){ p.mouseReleased(); } }); /* attach( document, "keydown", function( e ){ keyPressed = true; p.key = e.keyCode + 32; var i, len = p.codedKeys.length; for( i=0; i < len; i++ ){ if( p.key == p.codedKeys[ i ] ){ switch(p.key){ case 70: p.keyCode = p.UP ; break; case 71: p.keyCode = p.RIGHT ; break; case 72: p.keyCode = p.DOWN ; break; case 69: p.keyCode = p.LEFT ; break; } p.key=p.CODED; } } if( e.shiftKey ){ p.key = String.fromCharCode(p.key).toUpperCase().charCodeAt( 0 ); } if( typeof p.keyPressed == "function" ){ p.keyPressed(); } else{ p.keyPressed = true; } }); attach( document, "keyup", function( e ){ keyPressed = false; if( typeof p.keyPressed != "function" ){ p.keyPressed = false; } if( p.keyReleased ){ p.keyReleased(); } }); function attach(elem, type, fn) { // if( elem.addEventListener ){ elem.addEventListener( type, fn, false ); } // else{ elem.attachEvent( "on" + type, fn ); } } */ }; return p; } })();