Welcome to TiddlyWiki created by Jeremy Ruston, Copyright © 2007 UnaMesa Association
Finally got my Processing Wiki up and running. Not... much here yet, and it's kind of scattered all over the place. More I learn, the better it'll get.
I found two cool '~TiddlyProcessing' sites:
*http://tiddlyprocessing-simon.tiddlyspot.com/
*http://whatfettle.com/2008/05/TiddlyProcessing/
They come with the [[ProcessingjsPlugin]], which allows for Processing //in// the Tiddlywiki. It's like a Processing \ Tiddlywiki mashup. This is based on the work by [[Josh Resig|http://ejohn.org/]] on [[Processing.js|http://ejohn.org/blog/processingjs/]]. That plugin is now installed on //my// tiddlywiki, so I'll be able to actually post working examples. Sweet.
See an example below, pulled this directly from http://whatfettle.com/2008/05/TiddlyProcessing/, as a proof of concept test that the plugin works.
----
The angle of each segment is controlled with the mouseX and mouseY position. The transformations applied to the first segment are also applied to the second segment because they are inside the same pushMatrix() and popMatrix() group.
<<Processing
float x = 50;
float y = 100;
float angle1 = 0.0;
float angle2 = 0.0;
float segLength = 50;
void setup() {
size(200, 200);
smooth();
strokeWeight(20.0);
stroke(0, 100);
}
void draw() {
background(226);
angle1 = (mouseX/float(width) - 0.5) * -PI;
angle2 = (mouseY/float(height) - 0.5) * PI;
pushMatrix();
segment(x, y, angle1);
segment(segLength, 0, angle2);
popMatrix();
}
void segment(float x, float y, float a) {
translate(x, y);
rotate(a);
line(0, 0, segLength, 0);
}
>>
Taken from [[basic/arm.html|http://ejohn.org/apps/processing.js/examples/basic/arm.html]]
These are my online notes while I learn [[Processing|http://www.processing.org/]]. What is Processing? From the site:
"//Processing is an open source programming language and environment for people who want to program images, animation, and interactions. It is used by students, artists, designers, researchers, and hobbyists for learning, prototyping, and production. It is created to teach fundamentals of computer programming within a visual context and to serve as a software sketchbook and professional production tool. Processing is an alternative to proprietary software tools in the same domain.//"
I still consider myself a 'Processing noob', and this wiki is constantly in flux as I learn new things.
''DISCLAIMER''
*I can't be blamed for anything misrepresented on this page! If it doesn't work, no finger-waving my direction.
*If you find something wrong, please tell me. I //am// trying to correctly learn this stuff.
*Since I work on a Windows system, the majority of the command line stuff I call out to is Win-centric. If you're using Lunix\Unix\OSX etc, I can't comment on how well things will work.
Below are a list of //all// the subjects (tiddlers) in the wiki. Note that there will be ones for site maintenance etc, that should be disregarded.
----
<<list all>>
*{{{.charAt}}}
*{{{.equals}}}
*{{{.indexOf}}}
*{{{.length}}}
*{{{.substring}}}
*{{{.toLowerCase}}}
*{{{.toUpperCase}}}
Also see:
*[[List of array functions]]
*[[List of string functions]]
The most common way of setting up your sketch is to have a {{{setup()}}} function, and then a {{{draw()}}} function. {{{setup()}}} executes once, when the sketch starts. {{{draw()}}} executes every frame.
{{{
// any global variables would be defined here //
void setup(){
// Some common settings:
size(200, 200);
background(51);
noStroke();
smooth();
}
void draw(){
// do your stuff, will execute every frame.
}
}}}
<<gradient horiz #ffffff #ddddff #8888ff >>
The Processing Wiki blog
*[[2008 06 11]] - ~TiddlyProcessing!
*[[2008 06 10]] - Processing tiddlywiki is born!
Makes a bunch of balls bounce around the screen, and connects them by vibrating bezier curves.
Written while I was waiting on my computer to build the game I'm working on. Nothing terribly special about this, other than to teach myself how to use classes, expand arrays, and create simple motion. Good starting point for more complex stuff.
[img[http://bp3.blogger.com/_vouolqPGlUc/SHfoE0ffhvI/AAAAAAAABlg/Tg6rNad7yMc/s320/fuzzBall01.jpg]]
{{{
int ballCount = 10;
int c = 0;
Fball[] baller = {};
void setup(){
size(256, 256);
smooth();
// baller[0] = new Fball();
frameRate(30);
background(0);
}
void draw(){
fill(0,64);
quad(0,0, width, 0, width, height, 0, height);
while(c < ballCount){
baller = (Fball[])expand(baller, c+1);
println(baller.length);
baller[c] = new Fball();
c++;
}
for(int i=0; i<baller.length; i++){
baller[i].moveBall();
baller[i].drawLine();
baller[i].drawBall();
}
}
class Fball{
// Properties
private float drag = 1;
private float xPos;
private float yPos;
private float diameter;
private float xVelocity;
private float yVelocity;
private float xDir = 1;
private float yDir = 1;
// Constructors
Fball(){
diameter = random(8,64);
xPos = random(0+diameter/2, width-diameter/2);
yPos = random(0+diameter/2, height-diameter/2);
xVelocity = random (1, 4);
yVelocity = random (1, 4);
}
// Methods
float[] getPos(){
float[] r = {
xPos, yPos };
return r;
}
void drawBall(){
stroke(0);
strokeWeight(0);
fill(255,128);
ellipse(xPos, yPos, diameter, diameter);
}
void moveBall(){
xPos = xPos + ( xVelocity * xDir );
yPos = yPos + ( yVelocity * yDir );
xVelocity *= drag;
yVelocity *= drag;
// Test to see if the shape exceeds the boundaries of the screen
// If it does, reverse its direction by multiplying by -1
if (xPos > width-(diameter/2) || xPos < diameter/2) {
xDir *= -1;
}
if (yPos > height-(diameter/2) || yPos < diameter/2) {
yDir *= -1;
}
}
void drawLine(){
for(int i =0; i<baller.length; i++){
float[] targetPos = baller[i].getPos();
strokeWeight(1);
stroke(255);
noFill();
bezier(
xPos, yPos,
random(xPos-30, xPos+30), random(yPos-30, yPos+30),
random(targetPos[0]-30, targetPos[0]+30), random(targetPos[1]-30, targetPos[1]+30),
targetPos[0], targetPos[1]);
}
}
}
}}}
{{{
sqrt(abs(
pow(x2 - x1, 2) +
pow(y2 - y1, 2)));
}}}
Also known as associative arrays: Well, sort of, via Java. I pulled this from [[this thread|http://processing.org/discourse/yabb_beta/YaBB.cgi?board=LibraryProblems;action=display;num=1189615216;start=1#1]]
{{{
import java.util.HashMap;
HashMap hm = new HashMap();
hm.put("mykey","myvalue");
println(hm.get("mykey"));
hm.put(new Integer(7),new Integer(10));
println(hm.get(new Integer(7)));
}}}
According to the Java docs, the ~HashMap only takes in [[objects|class]]. From the above example, {{{strings}}} pass in fine, since {{{strings}}} in processing //are// objects. But to use something else, like an {{{int}}}, you need to make a {{{new Integer}}} object, and pass that in instead.
The problem I've found is that while per the example, you can print the return just fine, actually putting that retun into some kind of variable simply doesn't work. There seems to be some incompatibility.
*Java Docs on ~HashMap [[here|http://java.sun.com/j2se/1.4.2/docs/api/java/util/HashMap.html]]
''Update'': Fixed code pasted below. There was a slight formatting error when I transfered it to the wiki.
----
I authored this class to help with my "colorSearch" Sketch. You can see images from that sketch [[here|http://www.flickr.com/photos/warpcat/2597180052/]].
*During creation, you pass into this class an array of color data/pixels (say, via a {{{PImage.pixels}}} color array), and the width of the image the pixels were captured from.
*Then, via its method {{{get_colorPos}}}, you can pass in a color value. The method will return back the XY position of //every color in the image that matches//, into a 2d int array. Parse the array, and do stuff with the results.
*The 2d array's first array is the length of all the x match values. The second array holds only a single value, the matching y position. So for example, if you found four matching positions, the array size would be {{{[4][2]}}} (four indices 'long', and two indices 'wide').
*Example usage at the bottom explaining how to parse it.
{{{
/*
Eric Pavey - 2008-06-20
*/
class ImageData{
//------------------
// PROPERTIES:
// arrays to hold the xy pos for each pixel relative
// to the colors in pixies:
color[] pixies;
int[] xList;
int[] yList;
//------------------
// CONSTRUCTOR:
// Pass in a list of pixel values,
// and the width of the image they were captured from:
ImageData(color[] pix, int xRes){
pixies = pix;
xList = new int[pixies.length];
yList = new int[pixies.length];
// fill our xList and yLists:
int ix=0;
int iy=0;
for(int i=0; i<pixies.length; i++){
xList[i] = ix;
yList[i] = iy;
ix++;
if(ix > xRes-1){
ix=0;
iy++;
}
}
}
//------------------
// METHODS:
// Based on a passed in color, return back the x & y pos
// of every matching color in the image:
// color col : the color we're trying to match
int[][] get_colorPos(color col){
int[][] returnPos;
int[] foundX = new int[0];
int[] foundY = new int[0];
int counter=0;
for(int i=0; i<pixies.length; i++){
if(pixies[i] == col){
foundX = expand(foundX, counter+1);
foundY = expand(foundY, counter+1);
foundX[counter] = xList[i];
foundY[counter] = yList[i];
counter++;
}
}
// create our 2d array that will be returned
returnPos = new int[foundX.length][2];
// and fill the array with our found values:
for(int i=0; i<foundX.length; i++){
for(int j=0; j<2; j++){
if(j==0){
returnPos[i][j] = foundX[i];
}
else{
returnPos[i][j] = foundY[i];
}
}
}
return returnPos;
}
}
}}}
Example Usage:
{{{
// load our image:
PImage img = loadImage("myImage.jpg");
// Define some color to search for:
color searchCol = img.pixels[0];
// Create our ImageData object:
ImageData id = new ImageData(img.pixels, img.width);
// Find matching colors:
int[][] matchCols = id.get_colorPos(searchCol);
// do something with the colors:
for(int i=0;i<matchCols.length; i++){
println("Matching color at x: " + matchCols[i][0] + " y: " + matchCols[i][1]);
}
}}}
/***
|''Name:''|CryptoFunctionsPlugin|
|''Description:''|Support for cryptographic functions|
***/
//{{{
if(!version.extensions.CryptoFunctionsPlugin) {
version.extensions.CryptoFunctionsPlugin = {installed:true};
//--
//-- Crypto functions and associated conversion routines
//--
// Crypto "namespace"
function Crypto() {}
// Convert a string to an array of big-endian 32-bit words
Crypto.strToBe32s = function(str)
{
var be = Array();
var len = Math.floor(str.length/4);
var i, j;
for(i=0, j=0; i<len; i++, j+=4) {
be[i] = ((str.charCodeAt(j)&0xff) << 24)|((str.charCodeAt(j+1)&0xff) << 16)|((str.charCodeAt(j+2)&0xff) << 8)|(str.charCodeAt(j+3)&0xff);
}
while (j<str.length) {
be[j>>2] |= (str.charCodeAt(j)&0xff)<<(24-(j*8)%32);
j++;
}
return be;
};
// Convert an array of big-endian 32-bit words to a string
Crypto.be32sToStr = function(be)
{
var str = "";
for(var i=0;i<be.length*32;i+=8)
str += String.fromCharCode((be[i>>5]>>>(24-i%32)) & 0xff);
return str;
};
// Convert an array of big-endian 32-bit words to a hex string
Crypto.be32sToHex = function(be)
{
var hex = "0123456789ABCDEF";
var str = "";
for(var i=0;i<be.length*4;i++)
str += hex.charAt((be[i>>2]>>((3-i%4)*8+4))&0xF) + hex.charAt((be[i>>2]>>((3-i%4)*8))&0xF);
return str;
};
// Return, in hex, the SHA-1 hash of a string
Crypto.hexSha1Str = function(str)
{
return Crypto.be32sToHex(Crypto.sha1Str(str));
};
// Return the SHA-1 hash of a string
Crypto.sha1Str = function(str)
{
return Crypto.sha1(Crypto.strToBe32s(str),str.length);
};
// Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words
Crypto.sha1 = function(x,blen)
{
// Add 32-bit integers, wrapping at 32 bits
add32 = function(a,b)
{
var lsw = (a&0xFFFF)+(b&0xFFFF);
var msw = (a>>16)+(b>>16)+(lsw>>16);
return (msw<<16)|(lsw&0xFFFF);
};
// Add five 32-bit integers, wrapping at 32 bits
add32x5 = function(a,b,c,d,e)
{
var lsw = (a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF)+(e&0xFFFF);
var msw = (a>>16)+(b>>16)+(c>>16)+(d>>16)+(e>>16)+(lsw>>16);
return (msw<<16)|(lsw&0xFFFF);
};
// Bitwise rotate left a 32-bit integer by 1 bit
rol32 = function(n)
{
return (n>>>31)|(n<<1);
};
var len = blen*8;
// Append padding so length in bits is 448 mod 512
x[len>>5] |= 0x80 << (24-len%32);
// Append length
x[((len+64>>9)<<4)+15] = len;
var w = Array(80);
var k1 = 0x5A827999;
var k2 = 0x6ED9EBA1;
var k3 = 0x8F1BBCDC;
var k4 = 0xCA62C1D6;
var h0 = 0x67452301;
var h1 = 0xEFCDAB89;
var h2 = 0x98BADCFE;
var h3 = 0x10325476;
var h4 = 0xC3D2E1F0;
for(var i=0;i<x.length;i+=16) {
var j,t;
var a = h0;
var b = h1;
var c = h2;
var d = h3;
var e = h4;
for(j = 0;j<16;j++) {
w[j] = x[i+j];
t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
}
for(j=16;j<20;j++) {
w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
}
for(j=20;j<40;j++) {
w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k2);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
}
for(j=40;j<60;j++) {
w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
t = add32x5(e,(a>>>27)|(a<<5),(b&c)|(d&(b|c)),w[j],k3);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
}
for(j=60;j<80;j++) {
w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k4);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
}
h0 = add32(h0,a);
h1 = add32(h1,b);
h2 = add32(h2,c);
h3 = add32(h3,d);
h4 = add32(h4,e);
}
return Array(h0,h1,h2,h3,h4);
};
}
//}}}
Reference:
http://www.2dcurves.com/spiral/spiralaa.html
{{{
r = theta
}}}
Give it a second to get going....
<<Processing
float theta = 0;
void setup(){
size(256,256);
smooth();
}
void draw(){
translate(width/2, height/2);
float x = sin(theta);
float y = cos(theta);
point(x*theta,y*theta);
theta = theta + .01;
}
>>
Reference:
http://www.2dcurves.com/spiral/spirallo.html
The code I used to author this isn't exactly like listed, but gives a similar result. Need to revisit to make correct
{{{
r = pow(e, a*theta)
}}}
Give it a second to get going....
<<Processing
float theta = 0;
float mult = 1;
void setup(){
size(256,256);
smooth();
}
void draw(){
translate(width/2, height/2);
float x = sin(theta);
float y = cos(theta);
point(x*theta*mult,y*theta*mult);
theta = theta + .01;
mult = mult + .0025;
}
>>
{{{
y = x*x
}}}
<<Processing
int x = 0;
int y = 0;
void setup(){
size(256,256);
}
void draw(){
if(x<=width||y<=height){
y = int(pow(x,2)*.004);
point(x,y);
x++;
}
}
>>
/***
|''Name:''|DeprecatedFunctionsPlugin|
|''Description:''|Support for deprecated functions removed from core|
***/
//{{{
if(!version.extensions.DeprecatedFunctionsPlugin) {
version.extensions.DeprecatedFunctionsPlugin = {installed:true};
//--
//-- Deprecated code
//--
// @Deprecated: Use createElementAndWikify and this.termRegExp instead
config.formatterHelpers.charFormatHelper = function(w)
{
w.subWikify(createTiddlyElement(w.output,this.element),this.terminator);
};
// @Deprecated: Use enclosedTextHelper and this.lookaheadRegExp instead
config.formatterHelpers.monospacedByLineHelper = function(w)
{
var lookaheadRegExp = new RegExp(this.lookahead,"mg");
lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = lookaheadRegExp.exec(w.source);
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
var text = lookaheadMatch[1];
if(config.browser.isIE)
text = text.replace(/\n/g,"\r");
createTiddlyElement(w.output,"pre",null,null,text);
w.nextMatch = lookaheadRegExp.lastIndex;
}
};
// @Deprecated: Use <br> or <br /> instead of <<br>>
config.macros.br = {};
config.macros.br.handler = function(place)
{
createTiddlyElement(place,"br");
};
// Find an entry in an array. Returns the array index or null
// @Deprecated: Use indexOf instead
Array.prototype.find = function(item)
{
var i = this.indexOf(item);
return i == -1 ? null : i;
};
// Load a tiddler from an HTML DIV. The caller should make sure to later call Tiddler.changed()
// @Deprecated: Use store.getLoader().internalizeTiddler instead
Tiddler.prototype.loadFromDiv = function(divRef,title)
{
return store.getLoader().internalizeTiddler(store,this,title,divRef);
};
// Format the text for storage in an HTML DIV
// @Deprecated Use store.getSaver().externalizeTiddler instead.
Tiddler.prototype.saveToDiv = function()
{
return store.getSaver().externalizeTiddler(store,this);
};
// @Deprecated: Use store.allTiddlersAsHtml() instead
function allTiddlersAsHtml()
{
return store.allTiddlersAsHtml();
}
// @Deprecated: Use refreshPageTemplate instead
function applyPageTemplate(title)
{
refreshPageTemplate(title);
}
// @Deprecated: Use story.displayTiddlers instead
function displayTiddlers(srcElement,titles,template,unused1,unused2,animate,unused3)
{
story.displayTiddlers(srcElement,titles,template,animate);
}
// @Deprecated: Use story.displayTiddler instead
function displayTiddler(srcElement,title,template,unused1,unused2,animate,unused3)
{
story.displayTiddler(srcElement,title,template,animate);
}
// @Deprecated: Use functions on right hand side directly instead
var createTiddlerPopup = Popup.create;
var scrollToTiddlerPopup = Popup.show;
var hideTiddlerPopup = Popup.remove;
// @Deprecated: Use right hand side directly instead
var regexpBackSlashEn = new RegExp("\\\\n","mg");
var regexpBackSlash = new RegExp("\\\\","mg");
var regexpBackSlashEss = new RegExp("\\\\s","mg");
var regexpNewLine = new RegExp("\n","mg");
var regexpCarriageReturn = new RegExp("\r","mg");
}
//}}}
An improvement on my [[BouncyBalls01]] [[QUICKSKETCH]].
Find video of this on [[Flickr|http://www.flickr.com/photos/warpcat/2666229237/?processed=1&cb=1216016281234]]
[img[http://farm4.static.flickr.com/3117/2667707781_f53e412dba.jpg?v=0]]
(They're based on a slightly older version that what is represented below.
{{{
/*
FuzzBall03.06
Eric Pavey - 2008-07-13
User can use the mouse to create balls by pressing the LMB.
Reset with MMB.
Saves images with RMB.
Balls draw bezier curves to other balls if they are in range which allow them to apply
'pushing force' on one another. Otherwise, draw "searcher" lines. Balls push each
other around if they are in range, big balls have more force than small balls.
If you push "m", will turn on "magnetic" mode: Orange balls will attract, blue balls
will repulse.
Updates:
3.01: all balls now exert force on one another
3.02: LMB now creates new balls, much more interactive, and adds text
directions to splash screen.
3.03: Mouse motion now controls initial velocity and direction.
Number of balls printed to screen
3.04: Addition of 'checkState' method in Fball class: Will allow for
easier authoring of future behaviors.
3.05: MMB will now clear the screen, update splash screen
3.06: Adding ability for balls to push and pull.
*/
//----------------------------------------------------------
// user varaiable:
float minDiameter = 5;
float maxDiameter = 50;
int printBallNumber = 1;
//----------------------------------------------------------
// system vars, no touch
int c;
PFont fontA;
Fball[] baller = {};
float version = 3.06;
int magState = 0;
//----------------------------------------------------------
void setup(){
size(640, 480);
smooth();
frameRate(30);
background(0);
c=0;
fontA = createFont("Arial", 16, true);
}
//----------------------------------------------------------
void draw(){
// setup our background:
colorMode(HSB,100);
fill(0,30);
quad(0,0, width, 0, width, height, 0, height);
// if no balls exist, draw our instructions:
if(baller.length == 0){
drawSplash();
}
// draw our balls
for(int i=0; i<baller.length; i++){
baller[i].moveBall();
baller[i].checkState();
baller[i].drawBall();
}
// print # of balls:
if(printBallNumber == 1){
fill(0, 0, 100, 50);
text(("Number of balls: " + baller.length), 30, height - 35);
if(magState==1){
text(("Magnetic State: ON"), 30, height - 60);
}
else{
text(("Magnetic State: OFF"), 30, height - 60);
}
}
// mouse interaction:
if(mousePressed){
if(mouseButton == LEFT){
baller = (Fball[])expand(baller, baller.length+1);
baller[baller.length-1] = new Fball(minDiameter, maxDiameter);
}
if(mouseButton == CENTER){
baller = (Fball[])expand(baller, 0);
fill(0,30);
background(0);
}
if(mouseButton == RIGHT){
saveFrame("fuzzBall03-####.jpg");
println("Saved a frame");
}
}
if(keyPressed){
if(key == 'm'){
magState = abs(magState-1);
}
}
}
void drawSplash(){
textFont(fontA);
fill(0, 0, 100);
text("Press Left Mouse Button to create fuzzballs", 30, 60);
text("* Speed and direction of mouse effects fuzzball creation", 30, 90);
text("Press Middle Mouse Button to clear the screen", 30, 150);
text("Press Right Mouse Button to save an image", 30, 210);
text("Press 'm' (very quickly!) to toggle 'Magnetic State':", 30, 270);
text("* Orange balls will attract, blue balls repulse", 30, 300);
text("Fuzzballs v" + version, 30, height-10);
}
//----------------------------------------------------------
class Fball{
// Properties
float xPos;
float yPos;
float minDiameter;
float maxDiameter;
float diameter;
float xVelocity;
float yVelocity;
float xCurVelocity;
float yCurVelocity;
color cirCol;
float angle;
float colVal;
int attractOrPush;
float forceScale;
// Constructor
Fball(float minDiameter, float maxDiameter){
this.minDiameter = minDiameter;
this.maxDiameter = maxDiameter;
diameter = random(minDiameter,maxDiameter);
xPos = mouseX + random(-5, 5);
yPos = mouseY + random(-5, 5);
xCurVelocity = (mouseX-pmouseX) * .1;
yCurVelocity = (mouseY-pmouseY) * .1;
float velocity = (abs(xCurVelocity) + abs(yCurVelocity))/2;
if(velocity < 2){
velocity = 2;
}
xVelocity = velocity;
yVelocity = velocity;
// for some reason, this wouldn't do anything when in the
// draw() or setup() functions...
colorMode(HSB, 100);
attractOrPush = int(random(0,2));
// if we attract balls
if(attractOrPush == 0){
cirCol = color(random(0,10), random(50,100), random(75,100));
forceScale = -1;
}
else{
cirCol = color(random(50,60), random(50,100), random(75,100));
forceScale = 1;
}
colVal = brightness(cirCol);
angle = random(0, TWO_PI);
}
// Methods
float[] getPos(){
float[] r = {
xPos, yPos };
return r;
}
float getDiameter(){
return diameter;
}
void drawBall(){
stroke(cirCol);
strokeWeight(1);
fill(cirCol,32);
ellipse(xPos, yPos, diameter, diameter);
}
void applyForce(float forceX, float forceY, float force){
float vecX = xPos - forceX;
float vecY = yPos - forceY;
float vecLength = mag(vecX, vecY);
float normalX = vecX / vecLength;
float normalY = vecY / vecLength;
xCurVelocity = xCurVelocity + normalX * force * .01;
yCurVelocity = yCurVelocity + normalY * force * .01;
}
void moveBall(){
xPos = xPos + xCurVelocity;
yPos = yPos + yCurVelocity;
// Test to see if the shape exceeds the boundaries of the screen
// If it does, reverse its direction by multiplying by -1
if (xPos > width-(diameter/2)){
xCurVelocity = -xVelocity;
xPos = width-(diameter/2);
}
if(xPos < diameter/2) {
xCurVelocity = xVelocity;
xPos = diameter/2;
}
if (yPos > height-(diameter/2)){
yCurVelocity = -yVelocity;
yPos = height-(diameter/2);
}
if (yPos < diameter/2) {
yCurVelocity = yVelocity;
yPos = diameter/2;
}
}
void checkState(){
int foundCircle = 0;
// search through all of our circles:
for(int i=0; i<baller.length; i++){
// don't draw a line to itself
if(baller[i] != this){
// get the distance between the current ball, and the ball being tested:
float[] targetPos = baller[i].getPos();
float distance = sqrt(abs(
pow(targetPos[0]-xPos, 2) +
pow(targetPos[1]-yPos, 2)));
// If a ball is in-range, what should happen?
if(distance <= diameter*3){
foundCircle = 1;
drawLine(targetPos, baller[i]);
if(magState == 1){
baller[i].applyForce(xPos, yPos, (diameter*forceScale));
}
else{
baller[i].applyForce(xPos, yPos, diameter);
}
}
}
}
// if nothing is in-range of our ball:
if(foundCircle == 0){
drawSearcher();
}
}
void drawLine(float[] targetPos, Fball baller){
strokeWeight(2);
stroke(cirCol,128);
noFill();
// find the closest point on both of our circles, and draw a line
// between those points:
float sourceVecX = targetPos[0] - xPos;
float sourceVecY = targetPos[1] - yPos;
float sourceAngle = atan2(sourceVecX, sourceVecY) * -1 + HALF_PI;
float destVecX = xPos - targetPos[0];
float destVecY = yPos - targetPos[1];
float destAngle = atan2(destVecX, destVecY) * -1 + HALF_PI;
float sourcePointX = xPos + cos(sourceAngle)*(diameter/2);
float sourcePointY = yPos + sin(sourceAngle)*(diameter/2);
float destPointX = targetPos[0] + cos(destAngle)*(baller.getDiameter()/2);
float destPointY = targetPos[1] + sin(destAngle)*(baller.getDiameter()/2);
ellipse(destPointX, destPointY, diameter/4, diameter/4);
bezier(
sourcePointX, sourcePointY,
random(sourcePointX-diameter, sourcePointX+diameter), random(sourcePointY-diameter, sourcePointY+diameter),
random(destPointX-diameter, destPointX+diameter), random(destPointY-diameter, destPointY+diameter),
destPointX, destPointY);
}
void drawSearcher(){
strokeWeight(2);
stroke(cirCol,128);
noFill();
// plot a bezier between two points: One on the edge of the circle,
// and one some distance away:
float eX = xPos + cos(angle)*(diameter/2);
float eY = yPos + sin(angle)*(diameter/2);
float pX = xPos + cos(angle)*(diameter*1.5);
float pY = yPos + sin(angle)*(diameter*1.5);
angle += 10/diameter;
bezier(
eX, eY,
random(eX-diameter/2, eX+diameter/2), random(eY-diameter/2, eY+diameter/2),
random(pX-diameter/2, pX+diameter/2), random(pY-diameter/2, pY+diameter/2),
pX, pY);
ellipse(pX, pY, diameter/4, diameter/4);
}
}
}}}
An improvement on my [[FuzzBalls03]] sketch. ''Still wip.''
In a nutshell:
Pressing "p" (very quickly) will toggle between creating "push" or "pull" balls.
Pressing "f" (very quickly) will toggle on "follow" balls.
Pressing "e" (very quickly) will toggle on\off 'energy usage'.
Put each of the below code segments in it's own sketch tab, with the given name:
{{{FuzzBall04}}}
{{{
/*
FuzzBall04.00
Eric Pavey - 2008-07-13
User can use the mouse to create balls by pressing the LMB.
Reset with MMB.
Saves images with RMB.
Balls draw bezier curves to other balls if they are in range which allow them to apply
'pushing force' on one another. Otherwise, draw "searcher" lines. Balls push each
other around if they are in range, big balls have more force than small balls.
If you push "m", will turn on "magnetic" mode: Orange balls will attract, blue balls
will repulse.
Updates:
*/
//----------------------------------------------------------
// user varaiable:
float minDiameter = 5;
float maxDiameter = 50;
int printData = 1;
//----------------------------------------------------------
// system vars, no touch
float version = 4.00;
int c;
PFont fontA;
// should balls use energy, or not?
int useEnergy = 1;
// a list of ALL the balls in the scene:
Fball[] baller = {};
// just the PushPullBalls:
PushPullBall[] ppb = {};
int pushPullState =0;
// just the FollowBalls:
FollowBall[] fb = {};
// this defines the type of ball to create:
// 0 = push, 1 = pull, 2 = follow, 3 = ?
int creationState = 0;
//----------------------------------------------------------
void setup(){
size(640, 480);
smooth();
frameRate(30);
background(0);
c=0;
fontA = createFont("Arial", 16, true);
}
//----------------------------------------------------------
void draw(){
// setup our background:
colorMode(HSB,100);
fill(0,32);
quad(0,0, width, 0, width, height, 0, height);
// if no balls exist, draw our instructions:
if(baller.length == 0){
drawSplash();
}
// draw our balls, for each different type:
for(int i=0; i<ppb.length; i++){
ppb[i].run();
}
for(int i=0; i<fb.length; i++){
fb[i].run();
}
// print # of balls:
if(printData == 1){
drawData();
}
// mouse interaction:
if(mousePressed){
if(mouseButton == LEFT){
if(creationState == 0){
ppb = (PushPullBall[])expand(ppb, ppb.length+1);
ppb[ppb.length-1] = new PushPullBall("push", minDiameter, maxDiameter);
baller = (Fball[])expand(baller, baller.length+1);
baller[baller.length-1] = ppb[ppb.length-1];
}
else if(creationState == 1){
ppb = (PushPullBall[])expand(ppb, ppb.length+1);
ppb[ppb.length-1] = new PushPullBall("pull", minDiameter, maxDiameter);
baller = (Fball[])expand(baller, baller.length+1);
baller[baller.length-1] = ppb[ppb.length-1];
}
else if(creationState == 2){
fb = (FollowBall[])expand(fb, fb.length+1);
fb[fb.length-1] = new FollowBall(minDiameter, maxDiameter);
baller = (Fball[])expand(baller, baller.length+1);
baller[baller.length-1] = fb[fb.length-1];
}
}
if(mouseButton == CENTER){
ppb = (PushPullBall[])expand(ppb, 0);
fb = (FollowBall[])expand(fb, 0);
baller = (Fball[])expand(baller, 0);
fill(0,30);
background(0);
}
if(mouseButton == RIGHT){
saveFrame("fuzzBall04-####.jpg");
println("Saved a frame");
}
}
// keyboard interaction:
if(keyPressed){
if(key == 'p'){
pushPullState = abs(pushPullState-1);
creationState = pushPullState;
}
if(key == 'f'){
creationState = 2;
pushPullState = 0;
}
if(key == 'e'){
useEnergy = abs(useEnergy-1);
if(useEnergy == 0){
for(int i=0; i< baller.length; i++){
baller[i].setEnergy(100);
}
}
}
}
}
void drawData(){
fill(0, 0, 100, 50);
text(("Number of balls: " + baller.length), width - 145, height - 30);
if(useEnergy == 0){
text(("Energy Usage: OFF"), 30, height - 60);
}
else if(useEnergy == 1){
text(("Energy Usage: ON"), 30, height - 60);
}
if(creationState==0){
text(("Creation State: Push"), 30, height - 30);
}
else if(creationState == 1){
text(("Creation State: Pull"), 30, height - 30);
}
else if(creationState == 2){
text(("Creation State: Follow"), 30, height - 30);
}
}
void drawSplash(){
textFont(fontA);
fill(0, 0, 100);
text("Fuzzballs v" + version, 30, 30);
text("Press Left Mouse Button to create fuzzballs", 30, 60);
text("* Speed and direction of mouse effects fuzzball creation", 30, 90);
text("Press Middle Mouse Button to clear the screen", 30, 150);
text("Press Right Mouse Button to save an image", 30, 210);
// text("Press 'm' (very quickly!) to toggle 'Magnetic State':", 30, 270);
// text("* Orange balls will attract, blue balls repulse", 30, 300);
}
}}}
{{{Fball}}}
{{{
// This is the master ball, that all other balls inherit from
class Fball{
//---------------------------
// PROPERTIES
// current position:
float xPos;
float yPos;
// min\max diamater
float minDiameter;
float maxDiameter;
// derrived random diameter:
float diameter;
// creation velocity:
float xVelocity;
float yVelocity;
// current velocity:
float xCurVelocity;
float yCurVelocity;
// color
color cirCol;
// angle storage
float angle;
// name of ball
String name;
// curent juice level:
float energy;
// define what type of ball this is;
int cState;
//---------------------------
// CONSTRUCTOR
Fball(float minDiameter, float maxDiameter){
// setup our diameter:
this.minDiameter = minDiameter;
this.maxDiameter = maxDiameter;
diameter = random(minDiameter,maxDiameter);
// setup our initial position:
xPos = mouseX + random(-5, 5);
yPos = mouseY + random(-5, 5);
// setup our velocity:
xCurVelocity = (mouseX-pmouseX) * .1;
yCurVelocity = (mouseY-pmouseY) * .1;
float velocity = (abs(xCurVelocity) + abs(yCurVelocity))/2;
if(velocity < 2){
velocity = 2;
}
xVelocity = velocity;
yVelocity = velocity;
// for some reason, this wouldn't do anything when in the
// draw() or setup() functions...
colorMode(HSB, 100);
// setup our initial angle:
angle = random(0, TWO_PI);
// setup initial energy
energy = 100;
// define the type of ball that just got made
cState = creationState;
}
//---------------------------
// METHODS
void setEnergy(float energy){
this.energy = energy;
}
//---------------------------
// Get ball name
String getName(){
return name;
}
float getDistance(Fball ball){
float[] targetPos = ball.getPos();
float distance = sqrt(abs(
pow(targetPos[0]-xPos, 2) +
pow(targetPos[1]-yPos, 2)));
return distance;
}
//---------------------------
// Get bal position
float[] getPos(){
float[] r = {
xPos, yPos };
return r;
}
//---------------------------
// Get ball diameter
float getDiameter(){
return diameter;
}
//---------------------------
// get the type of ball this is:
int getCreationState(){
return cState;
}
//---------------------------
// Can be used to apply positive, or negative forces
// forceX and forceY and the positions the force is coming
// from relative to this ball.
void applyForce(float forceX, float forceY, float force){
float vecX = xPos - forceX;
float vecY = yPos - forceY;
float vecLength = mag(vecX, vecY);
float normalX = vecX / vecLength;
float normalY = vecY / vecLength;
xCurVelocity = xCurVelocity + normalX * force * .01;
yCurVelocity = yCurVelocity + normalY * force * .01;
}
//---------------------------
// based on current position and velocity, move ball.
// bounce off walls
void moveBall(){
xPos = xPos + xCurVelocity;
yPos = yPos + yCurVelocity;
// Test to see if the shape exceeds the boundaries of the screen
// If it does, reverse its direction by multiplying by -1
if (xPos > width-(diameter/2)){
xCurVelocity = -xVelocity;
xPos = width-(diameter/2);
}
if(xPos < diameter/2) {
xCurVelocity = xVelocity;
xPos = diameter/2;
}
if (yPos > height-(diameter/2)){
yCurVelocity = -yVelocity;
yPos = height-(diameter/2);
}
if (yPos < diameter/2) {
yCurVelocity = yVelocity;
yPos = diameter/2;
}
}
//---------------------------
// Draws a jittering line between two balls.
// baller is the name of the ball to draw a line to
void drawLine(Fball baller){
float[] targetPos = baller.getPos();
strokeWeight(2);
stroke(cirCol,128);
noFill();
// find the closest point on both of our circles, and draw a line
// between those points:
float sourceVecX = targetPos[0] - xPos;
float sourceVecY = targetPos[1] - yPos;
float sourceAngle = atan2(sourceVecX, sourceVecY) * -1 + HALF_PI;
float destVecX = xPos - targetPos[0];
float destVecY = yPos - targetPos[1];
float destAngle = atan2(destVecX, destVecY) * -1 + HALF_PI;
float sourcePointX = xPos + cos(sourceAngle)*(diameter/2);
float sourcePointY = yPos + sin(sourceAngle)*(diameter/2);
float destPointX = targetPos[0] + cos(destAngle)*(baller.getDiameter()/2);
float destPointY = targetPos[1] + sin(destAngle)*(baller.getDiameter()/2);
ellipse(destPointX, destPointY, diameter/4, diameter/4);
bezier(
sourcePointX, sourcePointY,
random(sourcePointX-diameter, sourcePointX+diameter), random(sourcePointY-diameter, sourcePointY+diameter),
random(destPointX-diameter, destPointX+diameter), random(destPointY-diameter, destPointY+diameter),
destPointX, destPointY);
}
//---------------------------
// Searcher line to draw. Usually drawn when nothing else is going on.
void drawSearcher(){
strokeWeight(2);
stroke(cirCol,128);
noFill();
// plot a bezier between two points: One on the edge of the circle,
// and one some distance away:
float eX = xPos + cos(angle)*(diameter/2);
float eY = yPos + sin(angle)*(diameter/2);
float pX = xPos + cos(angle)*(diameter*1.5);
float pY = yPos + sin(angle)*(diameter*1.5);
angle += 10/diameter;
bezier(
eX, eY,
random(eX-diameter/2, eX+diameter/2), random(eY-diameter/2, eY+diameter/2),
random(pX-diameter/2, pX+diameter/2), random(pY-diameter/2, pY+diameter/2),
pX, pY);
ellipse(pX, pY, diameter/4, diameter/4);
}
}
}}}
{{{FollowBall}}}
{{{
class FollowBall extends Fball{
// what ball does this one follow?
int followIndex=-1;
FollowBall(float minDiameter, float maxDiameter){
super(minDiameter, maxDiameter);
name = ("FollowBall_" + fb.length);
cirCol = color(random(30,40), random(50,100), random(75,100));
// what circle does this follow?
followIndex = fb.length;
}
//---------------------------
void drawBall(){
stroke(cirCol);
strokeWeight(1);
fill(cirCol,32);
ellipse(xPos, yPos, diameter, diameter);
}
//---------------------------
void behavior(){
if(followIndex < fb.length && followIndex != -1){
// if this follows someting, apply a force to push it to the parent:
//int index = fb.length-1;
int index = followIndex;
float distance = getDistance(fb[index]);
float scaler = distance / diameter;
float[] lastPos = fb[index].getPos();
applyForce(lastPos[0], lastPos[1], -10*scaler);
//drawLine(fb[followIndex]);
drawLine(fb[index]);
}
}
//---------------------------
void run(){
super.moveBall();
drawBall();
behavior();
}
}
}}}
{{{PushPullBall}}}
{{{
// These balls push other balls around, or pull other balls to them.
// If energy usage is on, pushing and pulling costs energy. When
// a balls energy hits zero, it goes into recharge mode, where it can't
// do any pushing or pulling until energy has recharged back to 100%.
class PushPullBall extends Fball{
//-----------------------------
// PROPERTIES:
// 1 or -1, depending on if it pushes, or pulls
float forceScale;
// is this ball in recharge mode or not?
int recharge = 0;
//-----------------------------
// CONSTRUCTOR:
PushPullBall(String pushPull, float minDiameter, float maxDiameter){
super(minDiameter, maxDiameter);
// define name pushPull should be either 'push', or 'pull':
name = (pushPull + "Ball_" + ppb.length);
// define color, and force:
if(pushPull == "push"){
cirCol = color(random(50,60), random(50,100), random(75,100));
forceScale = 1;
}
if(pushPull == "pull"){
cirCol = color(random(0,10), random(50,100), random(75,100));
forceScale = -1;
}
}
//-----------------------------
// METHODS:
//---------------------------
void drawBall(){
stroke(cirCol);
strokeWeight(1);
if(useEnergy == 1){
fill(cirCol,energy);
}
else{
fill(cirCol,32);
}
ellipse(xPos, yPos, diameter, diameter);
if(recharge == 1){
fill(cirCol, 100-energy);
stroke(cirCol, energy);
ellipse(xPos, yPos, (diameter * (energy*.02)), (diameter * (energy*.02)));
}
}
//---------------------------
void behavior(){
int foundCircle = 0;
// search through all of our circles:
for(int i=0; i<baller.length; i++){
// don't interact with itself:
if(baller[i] != this){
// get the distance between the current ball, and the ball being tested:
float[] targetPos = baller[i].getPos();
float distance = getDistance(baller[i]);
// If a ball is in-range, has enough energy; push or pull:
if(distance <= diameter*3 && energy > 0 ){
// if we're *not* currently recharging our ball...
if(recharge == 0){
float energyUsage=0;
// if we're pulling balls, stop pulling when they get close:
// also, don't pull other pull balls.
if(distance > diameter && forceScale == -1 && baller[i].getCreationState() != 1){
energyUsage = baller[i].getDiameter() / diameter * .5;
foundCircle = 1;
drawLine(baller[i]);
// scaler is used to reduce the forceScale the closer the
// target gets to our ball.
float scaler = distance / diameter;
baller[i].applyForce(xPos, yPos, (diameter*forceScale*scaler));
}
// if we're pushing balls, push them away no matter how close:
if(distance > diameter && forceScale == 1){
energyUsage = baller[i].getDiameter() / diameter;
foundCircle = 1;
drawLine(baller[i]);
baller[i].applyForce(xPos, yPos, (diameter*forceScale));
}
// if we're using energy, and we found a ball to use it on:
if(useEnergy==1 && foundCircle == 1){
// figure new energy:
if(energy > 0){
energy = energy - energyUsage;
}
// if we hit 0 energy, start recharge cycle
if(energy <= 0){
recharge = 1;
energy = 0;
}
}
}
}
}
}
// if nothing is in-range of our ball:
if(foundCircle == 0){
if(recharge == 0){
drawSearcher();
}
// recharge energy:
if(energy < 100){
energy++;
}
if(energy >= 100){
energy = 100;
recharge = 0;
}
}
}
//---------------------------
void run(){
super.moveBall();
drawBall();
behavior();
}
}
}}}
All {{{PImage}}} objects have a {{{.pixels[]}}} array, holding all their color value. If you an index in the array, how can you figure out what the xy value of that pixel is?
{{{
PImange img = loadImage("foo.jpg");
// The pixel in the array you want to find the xy val of.
// Remember, the array is zero based, so this is the 8th
// pixel.
int myPixel = 7;
int x = myPixel % img.width;
int y = myPixel / img.width;
println("Pixel '" + myPixel + "' is at position x:" + x + " y:" +y);
Pixel '7' is at position x:3 y:1
// Presuming your image is w4 h4 (16 pixels total).
// Again, remember that the coordinates are zero-based.
}}}
Basically the equation goes:
{{{
x = i % w;
y = i / w;
}}}
So you can use it for any kind of array, presuming you know the array's 'width'. But images make the most sense.
[[Dave's Short Trig Course|http://www.clarku.edu/~djoyce/trig/]]
Recommended to me, for all your trig needs.
A {{{unit vector}}} is a vector with the same direction of the source vector, but with lengh = 1. Also called //normalizing// the vector.
{{{
float vecX = 2;
float vecY = 3;
float vecLength = mag(vecX, vecY);
float normalX = vecX / vecLength;
float normalY = vecY / vecLength;
println("Original vector xy: " + vecX + ", " + vecY);
println("Normalized vector xy: " + normalX + ", " + normalY);
}}}
{{{
Original vector x,y: 2.0, 3.0
Normalized vector x,y: 0.5547002, 0.8320503
}}}
{{{
PImage img = loadImage("foo.jpg");
int w = img.width;
int h = img.height;
color c = img.get( int(random(0,w)), int(random(0,h)) );
}}}
It's important to have the {{{abs()}}} in there, or you could end up trying to calculate the {{{sqrt()}}} of some negative value (not so good). Using the {{{Pythagorean theorem}}}:
{{{
float dis = sqrt(abs(
pow(mouseX, 2) - pow(pmouseX, 2) +
pow(mouseY, 2) - pow(pmouseY, 2)));
}}}
Since I'm still learning trig... was trying to find a way to figure out what the angle was of a given vector. The below example has two a point with the x and y values equidistant from the origin. This would result in a line being drawn to it from the origin at a 45 deg angle:
{{{
float x1 = 5;
float y1 = 5;
float angle = atan2(x1, y1);
println(degrees(angle));
45
}}}
Check out ~JPGVideo:
http://www.ndrw.co.uk/
I've been using this simple little application to convert jpg sequences into avi files for upload to Flickr, and it works really well. Not a lot of options, but... it's not like you need a lot of options...
The {{{createGraphics()}}} function.
http://www.processing.org/learning/basics/creategraphics.html
http://www.processing.org/reference/createGraphics_.html
Please see my other example:
[[How can I match a point to the end of a line that has been rotated?]]
Processing has {{{sqrt}}}, but no 'cuberoot' command:
{{{
float num = 27.0;
float raise = 1.0 / 3.0;
println(pow(num, raise));
3.0;
}}}
You can access the fields of the [[PImage|http://www.processing.org/reference/PImage.html]] object:
{{{
PImage img = loadImage("foo.jpg");
int w = img.width;
int h = img.height;
}}}
Example found in Processing Hacks by 'antiplastik':
http://processing.org/hacks/doku.php?id=hacks:listing-files
Source:
{{{
/**
listing-files taken from http://processinghacks.com/hacks:listing-files
@author antiplastik
*/
// we'll have a look in the data folder
java.io.File folder = new java.io.File(dataPath(""));
// let's set a filter (which returns true if file's extension is .jpg)
java.io.FilenameFilter jpgFilter = new java.io.FilenameFilter() {
boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".jpg");
}
};
// list the files in the data folder, passing the filter as parameter
String[] filenames = folder.list(jpgFilter);
// get and display the number of jpg files
println(filenames.length + " jpg files in specified directory");
// display the filenames
for (int i = 0; i < filenames.length; i++) println(filenames[i]);
}}}
While a sketch is running you can author a [[function]] around the {{{keyPressed}}} system variable, that queries which key is pressed, via the {{{key}}} system variable:
{{{
void keyPressed()
{
if(key == "a") {
// do sometehing
}
}
}}}
While a sketch is running, you can author a [[function]] specifically to handle this. It wrappers the system variable {{{mousePressed}}}, and queries the system variable {{{mouseButton}}}:
{{{
void mousePressed(){
if(mouseButton == LEFT){
# do something...
}
if(mouseButton == CENTER){
# do something...
}
else if(mouseButton == RIGHT){
# do something...
}
}
}}}
{{{expand()}}}
To use though, some examples:
{{{
// here we declare an empty array:
float[] foo = {};
println(foo.length);
// prints 0
foo = expand(foo, 4);
println(foo.length);
// prints 4
}}}
The 2nd arg is always the size to make it. It's //not// "will add this much to the size".
However, this gets more complicated if you have an array of objects:
{{{
class Foo{
}
Foo[] data = {};
println(data.length);
// Prints 0
data = (Foo[])expand(data, 2);
println(data.length);
// Prints 2
}}}
As you can see, for some reason you need to call to your class in parenthesis {{{(Foo[])}}} //before// the {{{expand}}} command. This doesn't appear to be documented... :-S
Consider you have the hand of a clock spinning, and you want to position an item on the end of the hand, but not have that item rotate in space? Two solutions are provided below.
Example 1 uses push and popMatrix, so the circle is at the orgin. {{{lineLength}}} can also be considered the radius of the circle. The main computation is this:
{{{
float newX = lineLength * cos(rot-HALF_PI);
float newY = lineLength * sin(rot-HALF_PI);
}}}
Example 2 //doesn't// use any matrix work, and because of that uses a slightly different formula. {{{cirX}}} and {{{cirY}}} are the center of the defined circle:
{{{
float pX = cirX + cos(rot)*radius;
float pY = cirY + sin(rot)*radius;
}}}
----
Code: (for some reason, the [[ProcessingjsPlugin]] won't display this in the wiki)
Example 1: Using push and popMatrix:
{{{
// Translate a point to match the end point of a rotated line.
float rot = 0;
int w = 200;
int h = 200;
void setup(){
size(w, h);
background(0);
stroke(255);
strokeWeight(2);
smooth();
}
void draw(){
// fill our background each loop:
quad(0, 0, width, 0, width, height, 0, height);
// move the frame so the origin is at the middle bottom
// of the window:
translate(width/2, height/2);
//draw a circle to mark the origin point:
ellipse(0,0, 10,10);
// rotate our matrix, and draw a line:
pushMatrix();
rotate(rot);
float lineLength = height/4;
line(0, 0, 0, -lineLength);
popMatrix();
// create an ellipse at the location of the end of the
// line, but based on a different transformation matrix:
float newX = lineLength * cos(rot-HALF_PI);
float newY = lineLength * sin(rot-HALF_PI);
fill(0);
ellipse(newX, newY, 5, 15);
rot = rot + .01;
}
}}}
Example 2:
{{{
float radius = 40;
float rot = 0;
void setup(){
stroke(255);
strokeWeight(2);
smooth();
}
void draw(){
// fill our background each loop:
background(0);
// determine the center of our circle:
float cirX = width/2;
float cirY = height/2;
// draw our circle:
fill(0,255);
ellipse(cirX,cirY, radius*2,radius*2);
//draw a circle to mark the center point:
ellipse(cirX,cirY, 10,10);
// determine the point on the circumference of our circle:
float pX = cirX + cos(rot)*radius;
float pY = cirY + sin(rot)*radius;
// create an ellipse at the location of the end of the line:
stroke(128);
line(cirX, cirY, pX, pY);
fill(255);
ellipse(pX, pY, 5, 15);
rot = rot + .01;
}
}}}
{{{pixels[]}}} is a global system variable that stores all the pixels from the sketch screen. You load pixels into the array via the {{{loadPixels()}}} function. If you make any changes to the pixels in the array, you can apply them back to the screen with the {{{updatePixles}}} function.
http://www.processing.org/reference/pixels.html
http://www.processing.org/reference/loadPixels_.html
http://www.processing.org/reference/updatePixels_.html
{{{
loadPixels();
int totalPix = width * height;
for(int i=0; i<totalPix; i++){
// do work on pixels[$i];
}
updatePixels();
}}}
You can query via {{{g.}}} for certain values:
{{{
println(g.strokeWeight);
println(g.fill);
1.0
true
}}}
These are read only attributes. Here is a list, maybe more?
{{{
strokeWeight
smooth
strokeJoin
noSmooth
ellipseMode
rectMode
strokeCap
}}}
Via the 'Shape | Attributes' section in the extended reference.
using Java's {{{Random}}} class. Example is using an {{{int}}} array. If you wanted to use a different type of data, check the docs on Random [[here|http://java.sun.com/j2se/1.4.2/docs/api/java/util/Random.html]].
{{{
Random rand = new Random();
int[] myArray = {1,2,3,4,5};
int pos, temp;
for (int i=1; i<myArray.length; i++){
pos = rand.nextInt(i);
temp = myArray[pos];
myArray[pos] = myArray[i];
myArray[i] = temp;
}
for(int i=0; i<myArray.length; i++){
print(myArray[i] + " ");
}
3 1 4 5 2
}}}
Found from this post:
http://forum.java.sun.com/thread.jspa?threadID=731204&messageID=10009632
{{{
// add extra # symbols for more padding:
saveFrame("myFile####.jpg);
}}}
Mainly pulled from the book:
[[Processing: A Progamming Handbook for Visual Designers and Artists|http://mitpress.mit.edu/catalog/item/default.asp?ttype=2&tid=11251]]
Presuming you have an array of colors to pass in, it will return a new array of the colors sorted from darkest to lighest:
{{{
color[] palette_darkToLight(color[] colors){
color[] sorted = new color[colors.length];
int num = 0;
for(int i =0; i<255; i++){
for(int j=0; j<colors.length; j++){
if(int(brightness(colors[j])) == i){
sorted[num] = colors[j];
num++;
}
}
}
return sorted;
}
}}}
{{{
int winRes = 512;
int depth = winRes;
void setup(){
size(winRes, winRes, P3D);
}
void draw(){
background(128, 128);
lights();
// position to middle of screen
translate(width/2, height/2, -depth/4);
// have mouse control the rotation of the scene:
rotateX(map(mouseY, height, 0, 0, TWO_PI));
rotateY(map(mouseX, width, 0, 0, TWO_PI)) ;
box(128);
}
}}}
Any variable can be made into an array, and any array can can also be made into a 2D array by simply adding two sets of brackets. Like an array, the size of the 2d array needs to be defined during initialization:
{{{
int[][] foo = new int[5][2];
}}}
To iterate over a 2d array in a loop, you need to know the size of each array element.
To find the size of the __first array element__:
{{{
println(foo.length);
5
}}}
To find the size of the __second array element__, you need to specify a bracket[] after the variable name. You must put a number in the bracket, but the number doesn't seem to matter. I find this convention a bit odd:
{{{
println(foo[0].length);
2
}}}
To loop over a 2d array:
{{{
for(int i=0; i<foo.length; i++){
for(int j=0; j<foo[0].length; j++){
println("foo[" + i + "][" + j + "] = " + foo[i][j]);
}
}
foo[0][0] = 0
foo[0][1] = 0
foo[1][0] = 0
foo[1][1] = 0
etc...
}}}
Also see:
*[[Info on arrays]]
Any variable can be made into an array by adding square-brackets {{{[]}}} after its variable type. Arrays don't have a default data type, but are declared with a data type like variables are.
First an array is //declared//. Once declared, the type can't change:
{{{
// Array declaration:
float[] foo;
// foo will now be a float array, forever
}}}
After declaration, they are //initialized//. Array's need to use the [[new|http://www.processing.org/reference/new.html]] command:
{{{
// Array initialization.
foo = new float[50];
}}}
However, once initialized, their size can't changed (they become immutable sequences) without the help of the [[expand|http://www.processing.org/reference/expand_.html]] command.
Declaration and initialization can be combined into one statement:
{{{
float[] foo = new float[100];
}}}
Declaration can also assign the values at the same time, since this also determines the size:
{{{
int[] foo = {1,2,3};
}}}
However, things get a bit funny if you first initialize, //then// try to define with values:
{{{
int[] foo;
// this *won't* work:
foo = {1,2,3};
// this will work:
foo = new int[]{1,2,3};
}}}
Any object based on a [[class]] can be stored in an array based on it's type:
{{{
// make an array of ten 'foo' objects.
// Declare array:
Foo[] fooie;
// Initialize array size:
fooie = new Foo[10];
for(int i=0;i<10;i++){
fooie[i] = new Foo;
}
class Foo{
// stuff
}
}}}
''Arrays also have [[methods|Array and String methods]].''
Also see:
*[[Info on 2d Arrays]]
*[[What types of variables does Processing have?]]
*[[How can I randomize an array?]]
<<gradient horiz #ddddff #ffffff >>This is a [[TiddlyWiki|http://tiddlywiki.com/]]. To really get a grasp on how to navigate it, check out their [[homepage|http://tiddlywiki.com/]]. Quick directions below:
----
''SEARCHING FOR DATA:''
#You can do key-word searches in the search-field in the top of the //right column//.
#Browse the "Tags" tab in the //right column// for Processing-ish key-words.
**Inside the Tags tab, major ''Categories'' are all in caps, like "[[FUNDAMENTALS]]".
**When picking a 'Tag' with more than one link, you can either:
###'{{{Open all}}}' the topics in that Tag (meaning, fully expand all the topics listed in the middle of that pop-up menu).
###Open a single topic by picking its heading.
###Show all the headings in the Tag by picking: {{{Open tag 'tagname}}}'.
#Use your web browsers screen-search ability ('Ctrl+F' in both Firefox & Internet Explorer) to find key-words you're after (good if 'Tags' tab is open).
#Or start browsing from the ''Categories'' section in the //left column//. This will open each of their major headings in a new tiddler.
If things get too crowded, use the "close all" from the //right column// to clean up the page. Or, you can use "close others" from an individual tiddler (This block called "[[Instructions For Use]]" is a tiddler, for example).
----
''COPYING DATA FROM WIKI, TO PROCESSING:''
*The way the text has been entered into this wiki, copying code from the source-boxes should work:
{{{
source-code in a box;
}}}
*Other times it's not in a box, but is still safe for copy:
{{{source-code not in a box, but still safe to copy;}}}
*If you copy any code outside of a box that's 'not safe', Processing //may// have a hard time with it's formatting and be angered. Weird>>
/***
|''Name:''|LegacyStrikeThroughPlugin|
|''Description:''|Support for legacy (pre 2.1) strike through formatting|
|''Version:''|1.0.2|
|''Date:''|Jul 21, 2006|
|''Source:''|http://www.tiddlywiki.com/#LegacyStrikeThroughPlugin|
|''Author:''|MartinBudden (mjbudden (at) gmail (dot) com)|
|''License:''|[[BSD open source license]]|
|''CoreVersion:''|2.1.0|
***/
//{{{
// Ensure that the LegacyStrikeThrough Plugin is only installed once.
if(!version.extensions.LegacyStrikeThroughPlugin) {
version.extensions.LegacyStrikeThroughPlugin = {installed:true};
config.formatters.push(
{
name: "legacyStrikeByChar",
match: "==",
termRegExp: /(==)/mg,
element: "strike",
handler: config.formatterHelpers.createElementAndWikify
});
} //# end of "install only once"
//}}}
Some comments below the sketch code...
{{{
/*
Eric Pavey
2008-07-12
Draws two circles. Each circle has a line starting from its
border, pointing to the other circle based on the closest points
between the two circles.
The circles are authored through OOP. The line is drawn as a
normal function, simply to split it out of the objects, so it's
easier to visually debug.
Shows examples of:
* Calculating the closest point on the circumference of a
circle relative to another circle.
* Finding the point on the circumference of a circle based
on an angle.
Hold LMB to position c1, RMB to position c2
*/
//---------------------------------------------
// create our two circle objects:
Circle c1 = new Circle();
Circle c2 = new Circle();
//---------------------------------------------
void setup(){
size(512,512);
}
//---------------------------------------------
void draw(){
background(128);
c1.drawCircle();
c2.drawCircle();
drawLine();
// mouse control:
if(mousePressed){
if(mouseButton == LEFT){
c1.setPos(mouseX, mouseY);
}
if(mouseButton == RIGHT){
c2.setPos(mouseX, mouseY);
}
}
}
//---------------------------------------------
// Define our circle class:
class Circle{
float x;
float y;
float radius;
color col;
Circle(){
this.radius = 32;
this.col = color(random(0,255), random(0,255), random(0,255));
}
void drawCircle(){
fill(col);
ellipse(x, y, radius*2, radius*2);
}
float[] getPos(){
float pos[] = {
x, y};
return pos;
}
float getRadius(){
return radius;
}
void setPos(float x, float y){
this.x = x;
this.y = y;
}
}
//---------------------------------------------
// draw line between circles:
void drawLine(){
// get the xy position of both circles:
float[] c1Pos = c1.getPos();
float[] c2Pos = c2.getPos();
// get the vector from c1 to c2:
float c1VecX = c2Pos[0] - c1Pos[0];
float c1VecY = c2Pos[1] - c1Pos[1];
// get the vector from c2 to c1:
float c2VecX = c1Pos[0] - c2Pos[0];
float c2VecY = c1Pos[1] - c2Pos[1];
// based on our vectors, generate the angle that points from
// the center of one circle to the other:
float c1Angle = (atan2(c1VecX, c1VecY) * -1) + HALF_PI;
float c2Angle = (atan2(c2VecX, c2VecY) * -1) + HALF_PI;
// Create the line coordinates that draws from c1 to c2.
// The line starts at the radius of c1, and extends out to
// 2x the radius:
float c1CirX = c1Pos[0] + cos(c1Angle)*c1.getRadius();
float c1CirY = c1Pos[1] + sin(c1Angle)*c1.getRadius();
float c1OutX = c1Pos[0] + cos(c1Angle)*(c1.getRadius()*2);
float c1OutY = c1Pos[1] + sin(c1Angle)*(c1.getRadius()*2);
// Create the line coordinates that draws from c1 to c2.
// The line starts at the radius of c1, and extends out to
// 2x the radius:
float c2CirX = c2Pos[0] + cos(c2Angle)*c2.getRadius();
float c2CirY = c2Pos[1] + sin(c2Angle)*c2.getRadius();
float c2OutX = c2Pos[0] + cos(c2Angle)*(c2.getRadius()*2);
float c2OutY = c2Pos[1] + sin(c2Angle)*(c2.getRadius()*2);
// finally draw the line:
stroke(0);
line(c1CirX, c1CirY, c1OutX, c1OutY);
line(c2CirX, c2CirY, c2OutX, c2OutY);
}
}}}
When I was searching online on how to figure out the angle of a vector, I tracked down the {{{atan2}}} command. However, running this example block:
{{{
float c1Angle = atan2(c1VecX, c1VecY) ;
}}}
provided very poor results: The rotations were opposite, and off by 90 degrees. Through trial and error, I figured out the final block I used:
{{{ float c1Angle = (atan2(c1VecX, c1VecY) * -1) + HALF_PI;
float c2Angle = (atan2(c2VecX, c2VecY) * -1) + HALF_PI;
}}}
Which reverses the direction, and adds 90 degs to the angle. I don't know enough about trig yet to understand if I'm making a mistake in an earlier part of my code, or I simply need to do this. I'm just happy it works ;)
http://dev.processing.org/source/index.cgi/trunk/processing/core/src/processing/core/PConstants.java?view=markup
Also see:
*[[Processing system variables]]
[[shorten|http://www.processing.org/reference/shorten_.html]]
[[concat|http://www.processing.org/reference/concat_.html]]
[[subset|http://www.processing.org/reference/subset_.html]]
[[append|http://www.processing.org/reference/append_.html]]
[[sort|http://www.processing.org/reference/sort_.html]]
[[arraycopy|http://www.processing.org/reference/arraycopy_.html]]
[[reverse|http://www.processing.org/reference/reverse_.html]]
[[splice|http://www.processing.org/reference/splice_.html]]
[[expand|http://www.processing.org/reference/expand_.html]]
Also see:
*[[Array and String methods]]
[[split|http://www.processing.org/reference/split_.html]]
[[join|http://www.processing.org/reference/join_.html]]
[[splitTokens|http://www.processing.org/reference/splitTokens_.html]]
[[nf|http://www.processing.org/reference/nf_.html]]
[[match|http://www.processing.org/reference/match_.html]]
[[trim|http://www.processing.org/reference/trim_.html]]
[[nfc|http://www.processing.org/reference/nfc_.html]]
[[nfs|http://www.processing.org/reference/nfs_.html]]
[[nfp|http://www.processing.org/reference/nfp_.html]]
Also see:
*[[Array and String methods]]
/***
|''Name:''|LoadRemoteFileThroughProxy (previous LoadRemoteFileHijack)|
|''Description:''|When the TiddlyWiki file is located on the web (view over http) the content of [[SiteProxy]] tiddler is added in front of the file url. If [[SiteProxy]] does not exist "/proxy/" is added. |
|''Version:''|1.1.0|
|''Date:''|mar 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#LoadRemoteFileHijack|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
***/
//{{{
version.extensions.LoadRemoteFileThroughProxy = {
major: 1, minor: 1, revision: 0,
date: new Date("mar 17, 2007"),
source: "http://tiddlywiki.bidix.info/#LoadRemoteFileThroughProxy"};
if (!window.bidix) window.bidix = {}; // bidix namespace
if (!bidix.core) bidix.core = {};
bidix.core.loadRemoteFile = loadRemoteFile;
loadRemoteFile = function(url,callback,params)
{
if ((document.location.toString().substr(0,4) == "http") && (url.substr(0,4) == "http")){
url = store.getTiddlerText("SiteProxy", "/proxy/") + url;
}
return bidix.core.loadRemoteFile(url,callback,params);
}
//}}}
*[[Welcome]]
*[[About Processing Wiki]]
*[[Instructions for use]]
*[[Latest Updates|History]]
*[[Processing Links]]
*[[Blog]]
*[[About Author|WarpCat]]
----
''Subscribe:''
''[[RSS|http://processingwiki.tiddlyspot.com/index.xml]]'' [img[http://farm1.static.flickr.com/197/492915948_b4a9f3233e.jpg?v=0][http://processingwiki.tiddlyspot.com/index.xml]]
----
[[All Subjects]]
----
''Categories:''
[[ENVIRONMENT]]
[[FILESYSTEMS]]
[[FUNDAMENTALS]]
[[INFO]]
[[INTERACTION]]
[[MATH]]
[[I/O]]
[[OOP]]
[[PIXELS]]
[[PLAYBACK]]
[[QUICKSKETCH]]
[[TRANSFORMATION]]
[[VARIABLES]]
[[UI]]
Links:
*http://en.wikipedia.org/wiki/Matrix_%28mathematics%29
Check out stuff on {{{affine transform}}}
http://www.processing.org/reference/PImage.html
{{{get()}}} - Reads the color of any pixel or grabs a rectangle of pixels
{{{set()}}} - Writes a color to any pixel or writes an image into another
{{{copy()}}} - Copies the entire image
{{{mask()}}} - Masks part of the image from displaying
{{{blend()}}} - Copies a pixel or rectangle of pixels using different blending modes
{{{filter()}}} - Converts the image to grayscale or black and white
{{{save()}}} - Saves the image to a TIFF, TARGA, PNG, or JPEG file
You can also access these //fields//:
{{{.width}}} - Width of the image
{{{.height}}} - Height of the image
{{{.pixels[]}}} - Array of all pixels in the image.
{{{
/*
Eric Pavey - 2008-06-21
PixelPlot01
Based on the color values of an image, convert them
into x,y,z coordinates, and plot them in 3d space using
OpenGL.
Can use either RGB or HSB color space.
*/
import processing.opengl.*;
//---------------------------------
// USER VARS:
// Display window size:
int winRes = 512;
// color mode to use: RGB or HSB
String colMode = "HSB";
// Image to sample:
String imgPath = "image05.jpg";
// for performance reasons, downsample the image. This is
// the new X resolution of the image. Recomended values
// less than 100:
int resampleResX = 50;
// SYSTEM VARS:
int depth = winRes;
ColorPoint[] points;
PImage srcImg;
PImage img;
int itter = 0;
int resampleResY;
//---------------------------------
void setup(){
size(winRes, winRes, OPENGL);
noStroke();
perspective();
loop();
if(colMode == "RGB")
colorMode(RGB, 100);
else if(colMode == "HSB")
colorMode(HSB, 100);
// load our image, and then downsample it:
srcImg = loadImage(imgPath);
float resRatio = float(resampleResX) / float(srcImg.width);
resampleResY = int(float(srcImg.height) * resRatio);
img = srcImg.get(0,0,resampleResX,resampleResY);
img.copy(srcImg, 0, 0, srcImg.width, srcImg.height,
0, 0, resampleResX, resampleResY);
// load up our array of points to draw
points = new ColorPoint[img.pixels.length];
for(int i=0;i<img.pixels.length; i++){
points[i] = new ColorPoint(img.pixels[i]);
}
}
//---------------------------------
void draw(){
// show our downsized image in the upper left corner. This won't
// work using P3D, only OPENGL
background(img);
// position transformation matrix to middle of screen
translate(width/2, height/2, -depth/4);
// start spinning
rotateY(frameCount*PI/200);
rotateX(frameCount*PI/200);
// Start plotting pixels:
for(int i=0; i<itter; i++)
points[i].draw();
if(itter < img.pixels.length)
itter++;
else
println("Finished!");
}
//---------------------------------
class ColorPoint{
// Properties:
float xPos;
float yPos;
float zPos;
color pixCol;
// Constructor:
ColorPoint(color pix){
pixCol = pix;
// the '-100' is to help center it in the frame
if(colMode == "RGB"){
xPos = red(pix)-100;
yPos = green(pix)-100;
zPos = green(pix)-100;
}
else if(colMode == "HSB"){
xPos = hue(pix)-100;
yPos = saturation(pix)-100;
zPos = brightness(pix)-100;
}
}
// Method:
void draw(){
pushMatrix();
translate(xPos, yPos, zPos);
fill(pixCol,50);
box(winRes/100);
popMatrix();
}
}
}}}
''Official:''
*http://www.processing.org/
*[[Processing Extended Reference|http://www.processing.org/reference/index_ext.html]]
*[[Processing Core Reference|http://dev.processing.org/reference/core/]]
*[[Processing Forums|http://www.processing.org/discourse/yabb_beta/YaBB.cgi]]
----
''Java:''
*[[Java 2 Platform, Standard Edition, v 1.4.2 API Specification|http://java.sun.com/j2se/1.4.2/docs/api/index.html]] (Java classes for use in Processing)
*[[Sun's Java page on OOP|http://java.sun.com/docs/books/tutorial/java/concepts/index.html]]
----
''Inspiration:''
*[[Flickr|http://www.flickr.com/groups/processing/]] Group.
*[[Ben Fry|http://benfry.com/]]
*[[REAS.com|http://reas.com/]]
*[[Gallery of Computation|http://www.complexification.net/]]
*[[Flight404|http://www.flight404.com/blog/]]
*[[OpenProcessing|http://www.openprocessing.org/]]
----
''IDE's:''
*[[Obsessing|http://obsessing.org/]] : Author Processing in your browser.
*[[Lily Processing|http://blog.lilyapp.org/2008/05/processing_js_1.html]] : Visual programming in Processing.
----
''Informative:''
*[[Wikipedia|http://en.wikipedia.org/wiki/Processing_(programming_language)]]
*http://whatfettle.com/2008/05/TiddlyProcessing/ & http://tiddlyprocessing-simon.tiddlyspot.com/
**Sites with the [[ProcessingjsPlugin]], allowing for Processing execution //in// tiddywiki's.
----
''Recomended Books:''
*[[Processing: A Progamming Handbook for Visual Designers and Artists|http://mitpress.mit.edu/catalog/item/default.asp?ttype=2&tid=11251]]
**Downloads for this book can be found [[here|http://www.processing.org/learning/books/]]
*[[Processing: Creative Coding and Computational Art|http://www.friendsofed.com/book.html?isbn=159059617X]]
**Can download the lessons and example chapters there too.
----
''Similar to Processing'':
*[[Context Free Art|http://www.contextfreeart.org/]]
A list of system variables, or 'global variables' used in Processing. There are a few items that aren't officially 'system variables', but they act similarly.
|{{{frameCount}}} | the number of frames displayed since the program started|
|{{{frameRate}}} | the approximate frame rate of the software as it executes|
|{{{focused}}} | Confirms if a Processing program is "focused", meaning that it is active and will accept input from mouse or keyboard|
|{{{height}}} | the height of the window|
|{{{key}}} | contains the value of the most recent key on the keyboard that was used|
|{{{keyCode}}} | like key, but for non-ASCII keys|
|{{{keyPressed}}} | has a key been pressed?|
|{{{mouseX}}} | the current mouse X position|
|{{{mouseY}}} | the current mouse Y position|
|{{{pmouseX}}} | the previous frame's X mouse position|
|{{{pmouseY}}} | the previous frame's Y mouse position|
|{{{mouseButton}}} | which mouse button is pressed|
|{{{mousePressed}}} | variable storing if a mouse button is pressed|
|{{{online}}} | Confirms if a Processing program is running inside a web browser|
|{{{pixels[]}}} | An array Array containing the values for all the pixels in the display window. Must call the function {{{loadPixels()}}} first.|
|{{{PI}}} | 180 deg of a circle, or 1 radian. {{{3.14159265358979323846}}}|
|{{{HALF_PI}}} | 90 deg of a circle, or .5 radians. {{{1.57079632679489661923}}}|
|{{{TWO_PI}}} | 360 deg of a circle, or 2 radians. {{{6.28318530717958647693}}}|
|{{{screen}}} | the dimensions of the computer screen. Use .width & .height methods|
|{{{width}}} | the width of the window|
Also see:
*[[List of Processing Constants]]
/***
|''Name:''|ProcessingPlugin|
|''Description:''|TiddlyWiki Bundle of John Ressig's processing.js|
|''Date:''|May 9, 2008|
|''Author:''|PaulDowney (psd (at) osmosoft (dot) com)|
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/PaulDowney/plugins/ProcessingPlugin.js|
|''Version:''|0.2|
|''License:''|[[MIT license]]|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''~CoreVersion:''|2.2|
With contributions from Simon Baird.
***/
//{{{
// Ensure Plugin is only installed once.
if(!version.extensions.Processingjs) {
version.extensions.Processingjs = {installed:true};
config.macros.Processing = {
counter: 0,
handler: function (place,macroName,params,wikifier,paramString,tiddler) {
var id = "processingcanvas"+this.counter;
var canvas = createTiddlyElement(place,"canvas",id);
// inlined code
var code = paramString;
// quick and dirty grab of code from a named tiddler
if (store.tiddlerExists(params[0])) {
code = store.getTiddlerText(params[0]);
}
// or with no params, grab code from this tiddler
if (paramString.trim() == '') {
code = tiddler.text;
}
createTiddlyElement(place,"br");
var restartBtn = createTiddlyButton(place,"restart","restart",function() {
story.refreshTiddler(tiddler.title,null,true);
return false;
},
'processingRestart' // it's a class so you can style the button
);
Processing(canvas,code);
}
};
// requires 2.4
merge(config.macros.view.views,{
processing: function(value,place,params,wikifier,paramString,tiddler) {
wikify("<<Processing\n"+value+"\n>>",place,highlightHack,tiddler);
}
});
/*
* inlined copy of Processing.js
* latest code at: http://ejohn.org/blog/processingjs/
*/
/*
* 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" : "") +
"<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.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++ )