int WIDTH = 400; int HEIGHT = 400; int WH = WIDTH*HEIGHT; int[] DONE = new int[WH]; int MAXAGE; float RANGE = 6; int STILLRUNNING = 0; int blend(int org, int col, int alpha) { // org is original colour // col is colour to add // alpha is a value between 0 and 255, // where 0 makes 'col' completely opaque int r1=(org&0x0000ff); int g1=(org&0x00ff00); int b1=(org&0xff0000); int r2=(col&0x0000ff); int g2=(col&0x00ff00); int b2=(col&0xff0000); int r3=(((alpha*(r1-r2)) >>8 )+r2)&0x000000ff; int g3=(((alpha*(g1-g2)) >>8 )+g2)&0x0000ff00; int b3=(((alpha*(b1-b2)) >>8 )+b2)&0x00ff0000; return (r3)|(g3)|(b3); } void aapixel(float ax, float ay, int col, int alp) { int x = 0, y = 0; float fx = 0, fy = 0; x = (int)ax; y = (int)ay; fx = ax - x; fy = ay - y; pixels[x+y*WIDTH] = blend(col, pixels[x+y*width], (int)((1-fx)*(1-fy)*alp)); pixels[x+y*WIDTH+1] = blend(col, pixels[x+y*width+1], (int)((fx)*(1-fy)*alp)); pixels[x+y*WIDTH+width] = blend(col, pixels[x+y*width+width], (int)((1-fx)*(fy)*alp)); pixels[x+y*WIDTH+width+1] = blend(col, pixels[x+y*width+width+1], (int)((fx)*(fy)*alp)); } void blendcircle(int x, int y, int col, int radius, int alp) { float dist = 0; int zu = 0; // efficiency be damned! for(int i=0; i < radius*2; i++) { for(int u=0; u < radius*2; u++) { int ax = x + i - radius; if(ax < WIDTH && ax >= 0) { dist = sqrt(sq(i-radius)+sq(u-radius)); if(dist < radius) { zu = x-radius+i+(y+u-radius)*WIDTH; if(zu >= 0 && zu < WH) pixels[zu] = blend(col, pixels[zu], (int)(alp*(1-sqrt(dist/radius)))); } } } } } float dist(float x1, float y1, float x2, float y2) { return sqrt(sq(x1-x2) + sq(y1-y2)); } float[] sintable = new float[(int)(TWO_PI*1001)]; float[] costable = new float[(int)(TWO_PI*1001)]; class Edge { Edge e1; Edge e2; float startx, starty, endx, endy; float x, y, dir, dirvel; int[] xhist = new int[400]; int[] yhist = new int[400]; int running = 0; int exists = 0; int spawned = 0; int oldpos; int age; int col; int steps; int stopper = 0; // arr, a sea shanty it be. Edge(float xIn, float yIn, float dirIn, float dirvelIn, int ageIn, int colIn) { running = 1; startx = xIn; starty = yIn; x = xIn; y = yIn; dir = dirIn; dirvel = dirvelIn; exists = 1; spawned = 0; steps = 0; age = ageIn+1; col = colIn; stopper = 0; } void posupdate() { int next; dirvel += (dirvel < 0) ? -0.001 : 0.001;//random(-0.015, 0.015); //dirvel += 0.001; if(Math.abs(dirvel) > 0.15) { borked(); return; } if(Math.abs(dirvel) > 0.08 && stopper == 0) { stopper = steps; } dir += dirvel; dir = dir % TWO_PI; if(dir < 0) dir+=TWO_PI; steps++; x += sintable[(int)(dir*1000)]; y += costable[(int)(dir*1000)]; if(steps%3 == 1 && steps < 1200) { xhist[steps/3] = (int)x; yhist[steps/3] = (int)y; } next = (int)x + (int)y*WIDTH; if(x >= WIDTH || x <= 0 || y <= 0 || y >= HEIGHT-1 || next <= 0 || next >= WH || DONE[next] != 0 && oldpos != next && steps > 2) { borked(); } else if(next < WH-WIDTH-1 && next > 0) { DONE[next] = 1; aapixel(x, y, col, 20); STILLRUNNING = 1; } oldpos = next; } void borked() { if(age > MAXAGE) MAXAGE = age; running = 0; endx = x; endy = y; stroke(col); fill(col); //rect(startx, 0, endx-startx, height); blendcircle((int)endx, (int)endy, col, steps, (steps < 240) ? 255-steps:15 ); //line(startx, starty, endx, endy); //ellipse((int)endx, (int)endy, 9, 9); //if(dist(startx, starty, endx, endy) > RANGE) { if(steps > RANGE) { spawn(); } } void spawn() { int dir1; spawned = 1; int brightness; //brightness = (age < 32) ? 191 + age*2:255; brightness = (age*4)%255; int pos1, x1, y1; int pos2, x2, y2; if(stopper == 0) stopper = steps; pos1 = (int)random(stopper/3); pos2 = (int)random(stopper/3); if(pos1 > 399) pos1 = 399; if(pos2 > 399) pos2 = 399; x1 = xhist[pos1]; y1 = yhist[pos1]; x2 = xhist[pos2]; y2 = yhist[pos2]; int page = age/2; int mage = page%35; if(bursttype == 0) { e1 = new Edge(x1, y1, dir+PI/4+random(PI/2), random(-0.01, 0.01), age, color( 164- ((page%70 >= 35) ? 35-mage: mage) + random(9), 255-age, 255)); e2 = new Edge(x2, y2, dir-PI/4-random(PI/2), random(-0.01, 0.01), age, color( 164- ((page%70 >= 35) ? 35-mage: mage) + random(9), 255-age, 255)); } else { e1 = new Edge(x1, y1, dir+PI/4+random(PI/2), random(-0.01, 0.01), age, color( ((page%70 >= 35) ? 35-mage: mage) + random(9), 255-age, 255)); e2 = new Edge(x2, y2, dir-PI/4-random(PI/2), random(-0.01, 0.01), age, color( ((page%70 >= 35) ? 35-mage: mage) + random(9), 255-age, 255)); } //e1 = new Edge(x1, y1, dir+PI/4+random(PI/2), random(-0.01, 0.01), age, color( ((age%70 >= 35) ? 35-(age%35): age%35) + random(9), 255-age, 255)); //e2 = new Edge(x2, y2, dir-PI/4-random(PI/2), random(-0.01, 0.01), age, color( ((age%70 >= 35) ? 35-(age%35): age%35) + random(9), 255-age, 255)); //e1 = new Edge(x1, y1, dir+PI/4+random(PI/2), random(-0.01, 0.01), age, color( age*2 + random(20), 255-age, 255)); //e2 = new Edge(x2, y2, dir-PI/4-random(PI/2), random(-0.01, 0.01), age, color( age*2 + random(10), 255-age, 255)); xhist = null; yhist = null; } void update() { if(running == 1) posupdate(); if(spawned == 1) { e1.update(); e2.update(); } } } Edge e1; int bursttype; void setup() { size(400,400); colorMode(HSB); background(color(0, 0, 40)); noBackground(); startup(); ellipseMode(CENTER_DIAMETER); //fill(#fdfdfd); for(int i = 0; i < TWO_PI*1000; i++) { sintable[i] = sin(i/1000.0); costable[i] = cos(i/1000.0); } } void startup() { bursttype = (int)random(2); MAXAGE = 0; for(int i = 0; i < WIDTH*HEIGHT; i++) { pixels[i] = 0xff000000;//0xffffffff; DONE[i] = 0; } e1 = new Edge((int)random(WIDTH), (int)random(HEIGHT), random(TWO_PI), random(-0.01, 0.01), 0, color((int)random(255), 255, 196)); } void loop() { STILLRUNNING = 0; e1.update(); if(STILLRUNNING == 0) { if(MAXAGE > 5) {delay(5000);} else {delay(1000);} startup(); } }