////////////////////////////
// //
// doodle 3 //
// //
////////////////////////////
// (c) Martin Schneider 2009
int n = 1000;
int maxage = 20;
int rdodge = 30;
int opacity = 40;
float speed = .2;
float zoom = .01;
boolean crayons, soft, dodge = true;
float[][] a = new float[n][2];
int[] age = new int[n];
float w, h, s;
int t, c;
void setup() {
size(500, 500);
w = width/2;
h = height/2;
colorMode(HSB, TWO_PI, 2, 1);
smooth();
reset();
}
void draw() {
// create new particles
int np = n / maxage;
for(int i=0; i<np & c<n; i++, c++) newp(c);
// draw particle traces
for(int i=0; i<c; i++) {
age[i]++;
float[] p = a[i];
if (age[i] > maxage) newp(i);
else {
float[] f = f(p[0], p[1]);
// opacity based on speed (soft mode) or age (hard mode)
int m = maxage/2;
float o = soft ? mag(f[0], f[1]) * 2 * opacity : (m - abs(m - age[i])) * opacity/m;
// hue based on direction
float h = atan2(f[0], f[1]) + PI;
stroke(h, crayons ? 1 : 0, crayons ? 1 : 0, o);
// draw line while updating position
line(p[0], p[1], p[0] += s*f[0], p[1] += s*f[1]);
}
}
}
// noise based flow field
float[] f(float x, float y) {;
return new float[] {
noise(t, x * zoom, y * zoom)-.5,
noise(t+1, x * zoom, y * zoom) - .5
};
}
void newp(int p) {
if(dodge) {
// particle inside a circle around the mouse position
float r = random(rdodge), ang = random(TWO_PI);
a[p] = new float[] { mouseX + r * cos(ang), mouseY + r *sin(ang) };
} else {
// particle anywhere on screen
a[p] = new float[] { random(width), random(height) };
}
age[p] = 0;
}
void reset() {
background(crayons ? 0 : #ffffff);
s = speed / zoom;
c = 0;
}
void keyPressed() {
switch(key) {
case 's' : soft = !soft; break;
case 'd' : dodge = !dodge; break;
case 'f' : t++; break;
case 'c' : crayons = !crayons; break;
case '+' : zoom /= 1.1; break;
case '-' : zoom *= 1.1; break;
case ' ' : break;
default: return;
}
reset();
}