//
import java.util.*; public class puff extends PixApplet { Random R = new Random(0); int blur, mode = 0; double P[][]; double freq = 1./20; // THINGS TO INITIALIZE WHEN STARTING THE APPLET public void init() { super.init(); blur = W / 12; // CREATE CLOUD OF PARTICLES P = new double[700][3]; for (int i = 0 ; i < P.length ; i++) { double rr = 2; do { for (int j = 0 ; j < 3 ; j++) P[i][j] = 2 * (R.nextDouble() % 1) - 1; rr = dot(P[i],P[i]); } while (rr > 1); } } // DRAW THE PICTURE public void setPix(int frame) { super.setPix(frame); // FIRST SET ALL PIXELS TO BLACK for (int x = 0 ; x < W ; x++) for (int y = 0 ; y < H ; y++) pix[xy2i(x,y)] = 0; // THEN DRAW EACH PARTICLE for (int i = 0 ; i < P.length ; i++) { int x = (int)(W/2 + P[i][0] * (W/2-blur)); int y = (int)(H/2 + P[i][1] * (W/2-blur)); // MODE == 0: DISPLAY PARTICLE AS A POINT if (mode == 0) pix[xy2i(x,y)] = 255; // OTHERWISE, DISPLAY PARTICLE AS A BLURRY SPOT else for (int u = -blur ; u < blur ; u++) for (int v = -blur ; v < blur ; v++) pix[xy2i(x+u,y+v)] += Math.max(0, blur*blur - u*u - v*v); } // FINALLY, CONVERT CLOUD DENSITY TO PACKED R,G,B VALUES for (int x = 0 ; x < W ; x++) for (int y = 0 ; y < H ; y++) { int c = pix[xy2i(x,y)]; if (mode == 0) setPix(x,y, c,c,c); // MODE > 0: DO VARIOUS IMAGE PROCESSING else { // NORMALIZE THE BLURRY SPOT VALUES c = c * 256 / W * 256 / W / 55; setPix(x,y, c,c,c); if (mode >= 1) { if (c == 0) setPix(x,y, 0,0,0); else { double t = c / 255.; // MODE == 3 OR 4: ADD VARIOUS FREQUENCIES OF NOISE if (mode >= 4) t += .07 * Math.abs(ImprovedNoise.noise(2*freq*x,2*freq*y,.5)); if (mode >= 3) { t += .14 * Math.abs(ImprovedNoise.noise( freq*x, freq*y,.5)); t = Math.max(0, Math.min(1, t)); } // MODE > 1: APPLY HIGH CONTRAST FILTER TO CLOUD EDGES if (mode >= 2) c = (int)(255 * filter(t)); // BLEND OVER SKY COLOR setPix(x,y, c,c,c); } } } } } // HIGH CONTRAST FILTER TO BRING OUT THE CLOUD EDGES double filter(double t) { t = bias(t, .67); if (t < .5) t = gain(t, .86); t = bias(t, .35); return t; } // ALLOW EXTERNAL APPLICATION TO SET THE MODE public void setMode(int mode) { this.mode = mode; damage = true; } // DOT PRODUCT static double dot(double a[], double b[]) { double d = 0; for (int i = 0 ; i < a.length ; i++) d += a[i] * b[i]; return d; } // LINEAR INTERPOLATION static double lerp(double t, double a, double b) { return a + t * (b - a); } // BIAS AND GAIN FILTERS (FROM PERLIN '85) static final double LOG_HALF = Math.log(0.5); static double gain(double a, double b) { double p; if (a<.001) return 0.; else if (a>.999) return 1; b = (b<.001) ? .0001 : (b>.999) ? .999 : b; p = Math.log(1. - b) / LOG_HALF; if (a < 0.5) return Math.pow(2 * a, p) / 2; else return 1. - Math.pow(2 * (1. - a), p) / 2; } static double bias(double a, double b) { if (a < .001) return 0.; else if (a > .999) return 1.; else if (b < .001) return 0.; else if (b > .999) return 1.; else return Math.pow(a, Math.log(b) / LOG_HALF); } }