class SmokeSystem { Particle[] particle; Attractor[] attractor; PGraphics buf; float mx, my; int ALPH = 0x0f000000; color[] colours = { ALPH | 0x00ffffff, ALPH | 0x00ffff80, ALPH | 0x00ff8080 }; class Attractor { float x,y,vx,vy,px,py; float damp = 0.95; float accel = 1; Attractor() { x = px = random(buf.width); y = py = random(buf.height); vx = random(-accel/2,accel/2); vy = random(-accel/2,accel/2); } void step() { px = x; py = y; vx += (mx-x)/random(1.0,5.0); vy += (my-y)/random(1.0,5.0); x += vx; y += vy; vx *= damp; vy *= damp; } } class Particle { float x,y,vx,vy,px,py; float damp = 0.995; float accel = 0.5; int age = 0; int maxage = 100; Particle() { init(); } void init() { x = px = random(buf.width); y = py = random(buf.height); vx = random(-accel/2,accel/2); vy = random(-accel/2,accel/2); age = 0; maxage = (int)random(50,1500); } void step() { px = x; py = y; for (int i = 0; i < attractor.length; i++) { float d2 = sq(attractor[i].x-x) + sq(attractor[i].y-y); if (d2 > 0.1) { float id = 1.0 / d2; vx += accel * (attractor[i].x-x) * id; vy += accel * (attractor[i].y-y) * id; } } x += vx; y += vy; vx *= damp; vy *= damp; age++; if (age == maxage) { init(); } } } SmokeSystem(int p, int a, int w, int h) { buf = new PGraphics(w,h); buf.background(0); buf.noFill(); mx = mouseX * buf.width / width; my = mouseY * buf.height / height; attractor = new Attractor[a]; for (int i = 0; i < attractor.length; i++) { attractor[i] = new Attractor(); } particle = new Particle[p]; for (int i = 0; i < particle.length; i++) { particle[i] = new Particle(); } init_d(); } void run() { mx = mouseX * buf.width / width; my = mouseY * buf.height / height; buf.stroke(0); buf.rect(0,0,buf.width-1,buf.height-1); for (int j = 0; j < particle.length; j++) { buf.stroke(colours[j%colours.length]); buf.line(particle[j].x,particle[j].y,particle[j].px,particle[j].py); particle[j].step(); } for (int i = 0; i < attractor.length; i++) { attractor[i].step(); } dissipate(); buf.alpha(buf); } int[] d_kernel; int[] d_offset; int d_t; int[] pixels2; void init_d() { d_kernel = new int[]{ 0, 0, 0, 0, 1, 0, 10, 10, 10 }; d_offset = new int[]{ -buf.width-1, -buf.width, -buf.width+1, -1, 0, 1, buf.width-1, buf.width, buf.width+1 }; d_t = 0; for (int j = 0; j < d_offset.length; j++) { d_t += d_kernel[j]; } d_t = max(d_t,1); pixels2 = new int[buf.pixels.length]; } void dissipate() { System.arraycopy(buf.pixels,0,pixels2,0,buf.pixels.length); int r,g,b; for (int i = buf.width+1; i < buf.pixels.length-buf.width-1; i++) { if (i % buf.width == 0 || i % buf.width == buf.width-1) { i++; } r = g = b = 0; for (int j = 0; j < d_offset.length; j++) { int pix = i + d_offset[j]; r += d_kernel[j] * ((pixels2[pix] & 0xff0000) >> 16); g += d_kernel[j] * ((pixels2[pix] & 0x00ff00) >> 8); b += d_kernel[j] * ( pixels2[pix] & 0x0000ff); } r /= d_t; g /= d_t; b /= d_t; buf.pixels[i] = r << 16 | g << 8 | b; } } }