blob: 1eed8501fc32aa59a0e61d87ad9fdc18ad2db2eb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 ) {
if ( typeof aElement == "string" )
aElement = document.getElementById( aElement );
var p = buildProcessing( aElement );
if ( aCode )
p.init( aCode );
return p;
};
function log() {
try {
console.log.apply( console, arguments );
} catch(e) {
try {
opera.postError.apply( opera, arguments );
} catch(e){}
}
}
var parse = Processing.parse = 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" : "") +
"<CLASS " + name + " " + static + ">" + (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 = /<CLASS (\w+) (.*?)>/, 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.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;
// mouseButton constants: values adjusted to come directly from e.which
p.LEFT = 1;
p.CENTER = 2;
p.RIGHT = 3;
// "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 looping = 0;
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 curvePoints = [];
var curTightness = 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, secondX, secondY, 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;
p.mouseButton = 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;
// The current animation frame
p.frameCount = 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) * 360;
s = (s / greenRange) * 100;
b = (b / blueRange) * 100;
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 = {};
data.width = w;
data.height = h;
data.data = [];
if ( curContext.createImageData ) {
data = curContext.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;
};
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;
}
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] = 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;
}
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() {
clearInterval(looping);
};
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 ) {
curContext.save();
curContext.mozTextStyle = curTextSize + "px " + curTextFont.name;
var width = curContext.mozMeasureText( typeof str == "number" ?
String.fromCharCode( str ) :
str) / curTextSize;
curContext.restore();
return width;
} 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 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 ) {
return this.push( 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 == 1) {
redRange = mode == p.HSB ? 360 : 255;
}
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;
curvePoints = [];
};
p.endShape = function endShape( close ) {
if ( curShapeCount != 0 ) {
if ( close || doFill )
curContext.lineTo( firstX, firstY );
if ( doFill )
curContext.fill();
if ( doStroke )
curContext.stroke();
curContext.closePath();
curShapeCount = 0;
pathOpen = false;
}
if ( pathOpen ) {
if ( doFill )
curContext.fill();
if ( doStroke )
curContext.stroke();
curContext.closePath();
curShapeCount = 0;
pathOpen = false;
}
};
p.vertex = function vertex( x, y, x2, y2, x3, y3 ) {
if ( curShapeCount == 0 && curShape != p.POINTS ) {
pathOpen = true;
curContext.beginPath();
curContext.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 )
curContext.lineTo( x, y );
if ( curShape == p.TRIANGLE_STRIP ) {
if ( curShapeCount == 2 ) {
// finish shape
p.endShape(p.CLOSE);
pathOpen = true;
curContext.beginPath();
// redraw last line to start next shape
curContext.moveTo( prevX, prevY );
curContext.lineTo( x, y );
curShapeCount = 1;
}
firstX = prevX;
firstY = prevY;
}
if ( curShape == p.TRIANGLE_FAN && curShapeCount == 2 ) {
// finish shape
p.endShape(p.CLOSE);
pathOpen = true;
curContext.beginPath();
// redraw last line to start next shape
curContext.moveTo( firstX, firstY );
curContext.lineTo( x, y );
curShapeCount = 1;
}
if ( curShape == p.QUAD_STRIP && curShapeCount == 3 ) {
// finish shape
curContext.lineTo( prevX, prevY );
p.endShape(p.CLOSE);
pathOpen = true;
curContext.beginPath();
// redraw lines to start next shape
curContext.moveTo( prevX, prevY );
curContext.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 ) {
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 = 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.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();
}
p.frameCount++;
inDraw = true;
p.pushMatrix();
p.draw();
p.popMatrix();
inDraw = false;
};
p.loop = function loop() {
if ( loopStarted )
return;
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.round = function round( aNumber ) {
return Math.round( 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, obj ) {
if ( obj && obj.img ) {
p.image( obj, x, y );
} else {
var oldFill = curContext.fillStyle;
var color = obj;
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 = {};
pixels.width = p.width;
pixels.height = p.height;
pixels.data = [];
if ( curContext.createImageData ) {
pixels = curContext.createImageData( p.width, p.height );
}
var data = pixels.data;
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) {
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, "mousedown", function(e) {
mousePressed = true;
p.mouseButton = e.which;
if ( typeof p.mousePressed == "function" ) {
p.mousePressed();
} else {
p.mousePressed = true;
}
});
attach( curElement, "contextmenu", function(e) {
e.preventDefault();
e.stopPropagation();
});
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;
}
})();