/** * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS-IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Processing.js - John Resig (http://ejohn.org/) * MIT Licensed * http://ejohn.org/blog/processingjs/ * * This is a port of the Processing Visualization Language. * More information: http://processing.org/ */ (function(){ this.Processing = function Processing( aElement, aCode ) { var p = buildProcessing( aElement ); p.init( aCode ); return p; }; function log() { try { console.log.apply( console, arguments ); } catch(e) { try { opera.postError.apply( opera, arguments ); } catch(e){} } } function parse( aCode, p ) { // Angels weep at this parsing code :-( // Remove end-of-line comments aCode = aCode.replace(/\/\/ .*\n/g, "\n"); // Weird parsing errors with % aCode = aCode.replace(/([^\s])%([^\s])/g, "$1 % $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; } }); // 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.slice(1,-1).split("][").join(", ") + ")"; }); 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-z]\w*)(;|,)/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 )?(\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, "]") + "]"; }); // static { ... } blocks aCode = aCode.replace(/static\s*{((.|\n)*?)}/g, function(all, init) { // Convert the static definitons to variable assignments //return init.replace(/\((.*?)\)/g, " = $1"); return init; }); // super() is a reserved word aCode = aCode.replace(/super\(/g, "superMethod("); var classes = ["int", "float", "boolean", "string"]; function ClassReplace(all, name, extend, vars, last) { classes.push( name ); var static = ""; vars = vars.replace(/final\s+var\s+(\w+\s*=\s*.*?;)/g, function(all,set) { static += " " + 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?/g, ";\n 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 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"); function nextBrace( right ) { var rest = right; var position = 0; var leftCount = 1, rightCount = 0; while ( leftCount != rightCount ) { var nextLeft = rest.indexOf("{"); var 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); } // Handle (int) Casting aCode = aCode.replace(/\(int\)/g, "0|"); // Remove Casting aCode = aCode.replace(new RegExp("\\((" + classes.join("|") + ")(\\[\\])?\\)", "g"), ""); // Convert 3.0f to just 3.0 aCode = aCode.replace(/(\d+)f/g, "$1"); // Force numbers to exist //aCode = aCode.replace(/([^.])(\w+)\s*\+=/g, "$1$2 = ($2||0) +"); // Force characters-as-bytes to work aCode = aCode.replace(/('[a-zA-Z0-9]')/g, "$1.charCodeAt(0)"); // Convert #aaaaaa into color aCode = aCode.replace(/#([a-f0-9]{6})/ig, function(m, hex){ var num = toNumbers(hex); return "color(" + num[0] + "," + num[1] + "," + num[2] + ")"; }); function toNumbers( str ){ var ret = []; str.replace(/(..)/g, function(str){ ret.push( parseInt( str, 16 ) ); }); return ret; } //log(aCode); return aCode; } function buildProcessing( curElement ){ var p = {}; // init p.PI = Math.PI; p.TWO_PI = 2 * p.PI; p.HALF_PI = p.PI / 2; p.P3D = 3; p.CORNER = 0; p.CENTER = 1; p.CENTER_RADIUS = 2; p.RADIUS = 2; p.POLYGON = 1; p.TRIANGLES = 6; p.POINTS = 7; p.LINES = 8; p.TRIANGLE_STRIP = 9; p.CORNERS = 10; p.CLOSE = true; p.RGB = 1; p.HSB = 2; // "Private" variables used to maintain state var curContext = curElement.getContext("2d"); var doFill = true; var doStroke = true; var loopStarted = false; var hasBackground = false; var doLoop = true; var curRectMode = p.CORNER; var curEllipseMode = p.CENTER; var inSetup = false; var inDraw = false; var curBackground = "rgba(204,204,204,1)"; var curFrameRate = 1000; var curShape = p.POLYGON; var curShapeCount = 0; var opacityRange = 255; var redRange = 255; var greenRange = 255; var blueRange = 255; var pathOpen = false; var mousePressed = false; var keyPressed = false; var firstX, firstY, prevX, prevY; var curColorMode = p.RGB; var curTint = -1; var curTextSize = 12; var curTextFont = "Arial"; var getLoaded = false; var start = (new Date).getTime(); // Global vars for tracking mouse position p.pmouseX = 0; p.pmouseY = 0; p.mouseX = 0; p.mouseY = 0; // Will be replaced by the user, most likely 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; // In case I ever need to do HSV conversion: // http://srufaculty.sru.edu/david.dailey/javascript/js/5rml.js p.color = 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" ) { aColor = p.color( aValue1, aValue1, aValue1, opacityRange ); } else { aColor = p.color( redRange, greenRange, blueRange, opacityRange ); } // HSB conversion function from Mootools, MIT Licensed function HSBtoRGB(h, s, b) { h = (h / redRange) * 100; s = (s / greenRange) * 100; b = (b / blueRange) * 100; if (s == 0){ return [b, b, b]; } else { var hue = h % 360; var f = hue % 60; var br = Math.round(b / 100 * 255); 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.nf = function( num, pad ) { var str = "" + num; while ( pad - str.length ) str = "0" + str; return str; }; 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( this.images[ this.pos ], x, y ); if ( ++this.pos >= frames ) this.pos = 0; }; this.getWidth = function() { return getImage(this.images[0]).width; }; this.getHeight = function() { return getImage(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 = { width: w, height: h, pixels: new Array( w * h ), get: function(x,y) { return this.pixels[w*y+x]; }, _mask: null, mask: function(img) { this._mask = img; }, loadPixels: function() { }, updatePixels: function() { } }; return data; } p.createGraphics = function createGraphics( w, h ) { var canvas = document.createElement("canvas"); var ret = buildProcessing( canvas ); ret.size( w, h ); ret.canvas = canvas; return ret; } p.beginDraw = function beginDraw() { } p.endDraw = function endDraw() { } p.tint = function tint( rgb, a ) { curTint = a; } function getImage( img ) { if ( typeof img == "string" ) { return document.getElementById(img); } if ( img.img || img.canvas ) { return img.img || img.canvas; } img.data = []; for ( var i = 0, l = img.pixels.length; i < l; i++ ) { var c = (img.pixels[i] || "rgba(0,0,0,1)").slice(5,-1).split(","); img.data.push( parseInt(c[0]), parseInt(c[1]), parseInt(c[2]), 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; } p.image = function image( img, x, y, w, h ) { x = x || 0; y = y || 0; var obj = getImage(img); if ( curTint >= 0 ) { var oldAlpha = curContext.globalAlpha; curContext.globalAlpha = curTint / opacityRange; } if ( arguments.length == 3 ) { curContext.drawImage( obj, x, y ); } else { curContext.drawImage( obj, x, y, w, h ); } if ( curTint >= 0 ) { curContext.globalAlpha = oldAlpha; } if ( img._mask ) { var oldComposite = curContext.globalCompositeOperation; curContext.globalCompositeOperation = "darker"; p.image( img._mask, x, y ); curContext.globalCompositeOperation = oldComposite; } } p.exit = function exit() { } p.save = function save( file ) { } p.loadImage = function loadImage( file ) { var img = document.getElementById(file); if ( !img ) return; var h = img.height, w = img.width; var canvas = document.createElement("canvas"); canvas.width = w; canvas.height = h; var context = canvas.getContext("2d"); context.drawImage( img, 0, 0 ); var data = buildImageObject( context.getImageData( 0, 0, w, h ) ); data.img = img; return data; } p.loadFont = function loadFont( name ) { return { name: name, width: function( str ) { if ( curContext.mozMeasureText ) return curContext.mozMeasureText( typeof str == "number" ? String.fromCharCode( str ) : str) / curTextSize; else return 0; } }; } p.textFont = function textFont( name, size ) { curTextFont = name; p.textSize( size ); } p.textSize = function textSize( size ) { if ( size ) { curTextSize = size; } } p.textAlign = function textAlign() { } p.text = function text( str, x, y ) { if ( str && curContext.mozDrawText ) { curContext.save(); curContext.mozTextStyle = curTextSize + "px " + curTextFont.name; curContext.translate(x, y); curContext.mozDrawText( typeof str == "number" ? String.fromCharCode( str ) : str ); curContext.restore(); } } p.char = function char( key ) { //return String.fromCharCode( key ); return key; } p.println = function println() { } p.map = function map( value, istart, istop, ostart, ostop ) { return ostart + (ostop - ostart) * ((value - istart) / (istop - istart)); }; String.prototype.replaceAll = function(re, replace) { return this.replace(new RegExp(re, "g"), replace); }; p.Point = function Point( x, y ) { this.x = x; this.y = y; this.copy = function() { return new Point( x, y ); } } p.Random = function() { var haveNextNextGaussian = false; var 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; } }; } 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 i = 0; i < size; i++ ) { array[i] = 0; } } array.size = function() { return this.length; }; array.get = function( i ) { return this[ i ]; }; array.remove = function( i ) { return this.splice( i, 1 ); }; array.add = function( item ) { for ( var i = 0; this[ i ] != undefined; i++ ) {} this[ i ] = item; }; array.clone = function() { var a = new ArrayList( size ); for ( var i = 0; i < size; i++ ) { a[ i ] = this[ i ]; } return a; }; array.isEmpty = function() { return !this.length; }; array.clear = function() { this.length = 0; }; return array; } 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 ); } } p.beginShape = function beginShape( type ) { curShape = type; curShapeCount = 0; } p.endShape = function endShape( close ) { if ( curShapeCount != 0 ) { curContext.lineTo( firstX, firstY ); if ( doFill ) curContext.fill(); if ( doStroke ) curContext.stroke(); curContext.closePath(); curShapeCount = 0; pathOpen = false; } if ( pathOpen ) { curContext.closePath(); } } p.vertex = function vertex( x, y, x2, y2, x3, y3 ) { if ( curShapeCount == 0 && curShape != p.POINTS ) { pathOpen = true; curContext.beginPath(); curContext.moveTo( x, y ); } else { if ( curShape == p.POINTS ) { p.point( x, y ); } else if ( arguments.length == 2 ) { if ( curShape == p.TRIANGLE_STRIP && curShapeCount == 2 ) { curContext.moveTo( prevX, prevY ); curContext.lineTo( firstX, firstY ); } curContext.lineTo( x, y ); } else if ( arguments.length == 4 ) { if ( curShapeCount > 1 ) { curContext.moveTo( prevX, prevY ); curContext.quadraticCurveTo( firstX, firstY, x, y ); curShapeCount = 1; } } else if ( arguments.length == 6 ) { curContext.bezierCurveTo( x, y, x2, y2, x3, y3 ); curShapeCount = -1; } } prevX = firstX; prevY = firstY; firstX = x; firstY = y; curShapeCount++; if ( curShape == p.LINES && curShapeCount == 2 || (curShape == p.TRIANGLES || curShape == p.TRIANGLE_STRIP) && curShapeCount == 3 ) { p.endShape(); } if ( curShape == p.TRIANGLE_STRIP && curShapeCount == 3 ) { curShapeCount = 2; } } p.curveTightness = function() { } // Unimplmented - not really possible with the Canvas API p.curveVertex = function( x, y, x2, y2 ) { p.vertex( x, y, x2, y2 ); } p.bezierVertex = p.vertex p.rectMode = function rectMode( aRectMode ) { curRectMode = aRectMode; } p.imageMode = function() { } p.ellipseMode = function ellipseMode( aEllipseMode ) { curEllipseMode = aEllipseMode; } p.dist = function dist( x1, y1, x2, y2 ) { return Math.sqrt( Math.pow( x2 - x1, 2 ) + Math.pow( y2 - y1, 2 ) ); } 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.ortho = function ortho() { } p.translate = function translate( x, y ) { curContext.translate( x, y ); } p.scale = function scale( x, y ) { curContext.scale( x, y || x ); } p.rotate = function rotate( aAngle ) { curContext.rotate( aAngle ); } p.pushMatrix = function pushMatrix() { curContext.save(); } p.popMatrix = function popMatrix() { curContext.restore(); } p.redraw = function redraw() { if ( hasBackground ) { p.background(); } inDraw = true; p.pushMatrix(); p.draw(); p.popMatrix(); inDraw = false; } p.loop = function loop() { if ( loopStarted ) return; var looping = setInterval(function() { try { p.redraw(); } catch(e) { clearInterval( looping ); throw e; } }, 1000 / curFrameRate ); loopStarted = true; } p.frameRate = function frameRate( aRate ) { curFrameRate = aRate; } p.background = function background( img ) { if ( arguments.length ) { if ( img && img.img ) { curBackground = img; } else { curBackground = p.color.apply( this, arguments ); } } if ( curBackground.img ) { p.image( curBackground, 0, 0 ); } else { var oldFill = curContext.fillStyle; curContext.fillStyle = curBackground + ""; curContext.fillRect( 0, 0, p.width, p.height ); curContext.fillStyle = oldFill; } } p.sq = function sq( aNumber ) { return aNumber * aNumber; } p.sqrt = function sqrt( aNumber ) { return Math.sqrt( aNumber ); } p.int = function int( 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.ceil = function ceil( aNumber ) { return Math.ceil( aNumber ); } p.floor = function floor( aNumber ) { return Math.floor( aNumber ); } p.float = function float( aNumber ) { return typeof aNumber == "string" ? p.float( aNumber.charCodeAt(0) ) : parseFloat( aNumber ); } p.byte = function byte( aNumber ) { return aNumber || 0; } p.random = function random( aMin, aMax ) { return arguments.length == 2 ? aMin + (Math.random() * (aMax - aMin)) : Math.random() * aMin; } // From: http://freespace.virgin.net/hugo.elias/models/m_perlin.htm p.noise = function( x, y, z ) { return arguments.length >= 2 ? PerlinNoise_2D( x, y ) : PerlinNoise_2D( x, x ); } function Noise(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)); } function SmoothedNoise(x, y) { var corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16; var sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8; var center = Noise(x, y) / 4; return corners + sides + center; } 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); var v2 = SmoothedNoise(integer_X + 1, integer_Y); var v3 = SmoothedNoise(integer_X, integer_Y + 1); var v4 = SmoothedNoise(integer_X + 1, integer_Y + 1); var i1 = Interpolate(v1 , v2 , fractional_X); var i2 = Interpolate(v3 , v4 , fractional_X); return Interpolate(i1 , i2 , fractional_Y); } function PerlinNoise_2D(x, y) { var total = 0; var p = 0.25; var n = 3; for ( var i = 0; i <= n; i++ ) { var frequency = Math.pow(2, i); var amplitude = Math.pow(p, i); total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude; } return total; } function Interpolate(a, b, x) { var ft = x * p.PI; var f = (1 - p.cos(ft)) * .5; return a*(1-f) + b*f; } p.red = function( aColor ) { return parseInt(aColor.slice(5)); } p.green = function( aColor ) { return parseInt(aColor.split(",")[1]); } p.blue = function( aColor ) { return parseInt(aColor.split(",")[2]); } p.alpha = function( aColor ) { return parseInt(aColor.split(",")[3]); } 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.constrain = function constrain( aNumber, aMin, aMax ) { return Math.min( Math.max( aNumber, aMin ), aMax ); } p.sqrt = function sqrt( aNumber ) { return Math.sqrt( aNumber ); } p.atan2 = function atan2( aNumber, aNumber2 ) { return Math.atan2( aNumber, aNumber2 ); } p.radians = function radians( aAngle ) { return ( aAngle / 180 ) * p.PI; } p.size = function size( aWidth, aHeight ) { var fillStyle = curContext.fillStyle; var strokeStyle = curContext.strokeStyle; curElement.width = p.width = aWidth; curElement.height = p.height = aHeight; curContext.fillStyle = fillStyle; curContext.strokeStyle = strokeStyle; } p.noStroke = function noStroke() { doStroke = false; } p.noFill = function noFill() { doFill = false; } p.smooth = function smooth() { } p.noLoop = function noLoop() { doLoop = false; } p.fill = function fill() { doFill = true; curContext.fillStyle = p.color.apply( this, arguments ); } p.stroke = function stroke() { doStroke = true; curContext.strokeStyle = p.color.apply( this, arguments ); } p.strokeWeight = function strokeWeight( w ) { curContext.lineWidth = w; } p.point = function point( x, y ) { var oldFill = curContext.fillStyle; curContext.fillStyle = curContext.strokeStyle; curContext.fillRect( Math.round( x ), Math.round( y ), 1, 1 ); curContext.fillStyle = oldFill; } p.get = function get( x, y ) { if ( arguments.length == 0 ) { var c = p.createGraphics( p.width, p.height ); c.image( curContext, 0, 0 ); return c; } if ( !getLoaded ) { getLoaded = buildImageObject( curContext.getImageData(0, 0, p.width, p.height) ); } return getLoaded.get( x, y ); } p.set = function set( x, y, color ) { var oldFill = curContext.fillStyle; curContext.fillStyle = color; curContext.fillRect( Math.round( x ), Math.round( y ), 1, 1 ); curContext.fillStyle = oldFill; } p.arc = function arc( x, y, width, height, start, stop ) { if ( width <= 0 ) return; if ( curEllipseMode == p.CORNER ) { x += width / 2; y += height / 2; } curContext.beginPath(); curContext.moveTo( x, y ); curContext.arc( x, y, curEllipseMode == p.CENTER_RADIUS ? width : width/2, start, stop, false ); if ( doFill ) curContext.fill(); if ( doStroke ) curContext.stroke(); curContext.closePath(); } p.line = function line( x1, y1, x2, y2 ) { curContext.lineCap = "round"; curContext.beginPath(); curContext.moveTo( x1 || 0, y1 || 0 ); curContext.lineTo( x2 || 0, y2 || 0 ); curContext.stroke(); curContext.closePath(); } p.bezier = function bezier( x1, y1, x2, y2, x3, y3, x4, y4 ) { curContext.lineCap = "butt"; curContext.beginPath(); curContext.moveTo( x1, y1 ); curContext.bezierCurveTo( x2, y2, x3, y3, x4, y4 ); curContext.stroke(); curContext.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.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 == 0 && height == 0 ) return; curContext.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; } curContext.rect( Math.round( x ) - offsetStart, Math.round( y ) - offsetStart, Math.round( width ) + offsetEnd, Math.round( height ) + offsetEnd ); if ( doFill ) curContext.fill(); if ( doStroke ) curContext.stroke(); curContext.closePath(); } p.ellipse = function ellipse( x, y, width, height ) { x = x || 0; y = y || 0; if ( width <= 0 && height <= 0 ) return; curContext.beginPath(); if ( curEllipseMode == p.RADIUS ) { width *= 2; height *= 2; } var offsetStart = 0; // Shortcut for drawing a circle if ( width == height ) curContext.arc( x - offsetStart, y - offsetStart, width / 2, 0, Math.PI * 2, false ); if ( doFill ) curContext.fill(); if ( doStroke ) curContext.stroke(); curContext.closePath(); } p.link = function( href, target ) { window.location = href; } p.loadPixels = function() { p.pixels = buildImageObject( curContext.getImageData(0, 0, p.width, p.height) ).pixels; } p.updatePixels = function() { var colors = /(\d+),(\d+),(\d+),(\d+)/; var pixels = {}; var data = pixels.data = []; pixels.width = p.width; pixels.height = p.height; var 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] = parseInt(c[1]); data[pos+1] = parseInt(c[2]); data[pos+2] = parseInt(c[3]); data[pos+3] = parseFloat(c[4]) * 100; pos += 4; } curContext.putImageData(pixels, 0, 0); } 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; var 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; } } p.init = function init(code){ p.stroke( 0 ); p.fill( 255 ); // Canvas has trouble rendering single pixel stuff on whole-pixel // counts, so we slightly offset it (this is super lame). curContext.translate( 0.5, 0.5 ); 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(); } } attach( curElement, "mousemove", function(e) { p.pmouseX = p.mouseX; p.pmouseY = p.mouseY; p.mouseX = e.clientX - curElement.offsetLeft; p.mouseY = e.clientY - curElement.offsetTop; if ( p.mouseMoved ) { p.mouseMoved(); } if ( mousePressed && p.mouseDragged ) { p.mouseDragged(); } }); attach( curElement, "mousedown", function(e) { mousePressed = true; if ( typeof p.mousePressed == "function" ) { p.mousePressed(); } else { p.mousePressed = true; } }); attach( curElement, "mouseup", function(e) { mousePressed = false; 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; 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; } })();