class Subwave { float amplitude; float wavelength; float offset; float speed; Subwave(float aAmplitude, float aWavelength, float aOffset, float aSpeed) { amplitude = aAmplitude; wavelength = aWavelength; offset = aOffset; speed = aSpeed; } float position(float x) { return amplitude * sin( x / wavelength + offset ); } void update() { offset += speed; } } /** * */ class Wave { float[] path; float[] intensity; Subwave[] pathsub; Subwave[] intensitysub; float position; float length; float speed; boolean up; Wave() { path = new float[width]; intensity = new float[width]; length = random(width / 3, width * 2); speed = length / 100.0; speed = random(-speed, speed); position = -length; // Generate wave shape generate(); } void generatePathWave() { pathsub = new Subwave[(int)random(1, 4)]; for (int i = 0; i < pathsub.length; i++) { float wavelength = random(length / 8, length / 4); float amplitude = random(wavelength / 6, wavelength / 3); float offset = random(0, TWO_PI); float wavespeed = random(-0.002, 0.002); pathsub[i] = new Subwave(amplitude, wavelength, offset, wavespeed); } } void updatePathWave() { float amplitude = 0; for (int i = 0; i < pathsub.length; i++) { if (pathsub[i].amplitude > amplitude) { amplitude = pathsub[i].amplitude; } } for (int i = 0; i < width; i++) { path[i] = halfHeight + (amplitude) * (up ? 0.5 : -0.5); } for (int i = 0; i < pathsub.length; i++) { pathsub[i].update(); for (int j = 0; j < width; j++) { path[j] += pathsub[i].position(j); } } for (int i = 0; i < width; i++) { path[i] = constrain(path[i], 0, height); } } void generateIntensityWave() { intensitysub = new Subwave[(int)random(1, 3)]; for (int i = 0; i < intensitysub.length; i++) { float wavelength = random(width / 3.0, width); float amplitude = random(0, 1); float offset = random(0, TWO_PI); float wavespeed = random(-0.015, 0.015); intensitysub[i] = new Subwave(amplitude, wavelength, offset, wavespeed); } } void updateIntensityWave() { for (int i = 0; i < width; i++) { intensity[i] = 0; } for (int i = 0; i < intensitysub.length; i++) { intensitysub[i].update(); for (int j = 0; j < width; j++) { intensity[j] += intensitysub[i].position(j); } } for (int i = 0; i < width; i++) { intensity[i] = constrain(abs(intensity[i]), 0.05, 0.3); } } /** * */ void generate() { generatePathWave(); generateIntensityWave(); up = (random(0, 1) < 0.5); } /** * */ void update() { position += speed; updatePathWave(); updateIntensityWave(); if (speed < 0 && position + length < 0) { position = width; generate(); } else if (speed > 0 && position > width) { position = -length - random(0, length); generate(); } } /** * Adds the wave's image to the specified pixel array */ void composite(int pix[]) { int pos; for (int i = (int)position; i < (int)min(position + length, width); i++) { if (i < 0) {continue;} // (1-((float)i / width)) * float bright = 0.30 * constrain(1 - abs(position + (length / 2.0) - i) / (length / 2), 0.0, 1.0); float diff = path[i] - (int)path[i]; float waveheight = sin(bright * PI) * length / 2; for (int u = 0; u < waveheight; u++) { modPixel(pix, i + ((int)path[i] + (up ? -u : u)) * width, whiteToPix(intensity[i] * bright * (float)(waveheight - u) / waveheight), 2); } float lineBright = intensity[i] * bright * 0.6f; modPixel(pix, i + (int)path[i] * width, whiteToPix(lineBright * (1.0 - diff)), 1); modPixel(pix, i + (int)path[i] * width + width, whiteToPix(lineBright * diff), 1); } } // end class } int whiteToPix(float intensity) { return whiteToPix((int)(intensity * 255)); } int whiteToPix(int intensity) { return (intensity << 16 | intensity << 8 | intensity); } void modPixel(int pix[], int pos, int col, int type) { if (pos >= pix.length || pos < 0) { return; } switch (type) { case 1: pix[pos] = addPixels(pix[pos], col); break; case 2: pix[pos] = multiplyPixels(pix[pos], col); break; default: pix[pos] = col; } } int addPixels(int base, int pix) { int r1 = (base & 0x00ff0000) >> 16; int g1 = (base & 0x0000ff00) >> 8; int b1 = base & 0x000000ff; int r2 = (pix & 0x00ff0000) >> 16; int g2 = (pix & 0x0000ff00) >> 8; int b2 = pix & 0x000000ff; int r3 = (int)min(r1 + r2, 255) << 16; int g3 = (int)min(g1 + g2, 255) << 8; int b3 = (int)min(b1 + b2, 255); return 0xff000000 | (r3) | (g3) | (b3); } int multiplyPixels(int base, int pix) { int r1 = (base & 0x00ff0000) >> 16; int g1 = (base & 0x0000ff00) >> 8; int b1 = base & 0x000000ff; int r2 = (pix & 0x00ff0000) >> 16; int g2 = (pix & 0x0000ff00) >> 8; int b2 = pix & 0x000000ff; int r3 = min(r1 + (r1 * r2) / 200, 255) << 16; int g3 = min(g1 + (g1 * g2) / 200, 255) << 8; int b3 = min(b1 + (b1 * b2) / 200, 255); return 0xff000000 | (r3) | (g3) | (b3); } // global vars // static int NUM_WAVES = 15; // Wave[] wave; // PImage bg; // float halfHeight; void waveSetup() { println("setup..."); //size(800, 600); noStroke(); //framerate(30); halfHeight = height / 2.0; bg = new PImage(width, height); waveBackground = new PImage(width,height); for (int y = 0; y < height; y++) { float col = (1 - abs(y - halfHeight) / halfHeight) * 0.3; for (int x = 0; x < width; x++) { bg.pixels[x + y * width] = 0x064191; modPixel(bg.pixels, x + y * width, whiteToPix(col), 1); } } wave = new Wave[NUM_WAVES]; for (int i = 0; i < NUM_WAVES; i++) { wave[i] = new Wave(); } } PImage waveBackground; void drawWave() { //println("drawWave..."); waveBackground.loadPixels(); System.arraycopy(bg.pixels, 0, waveBackground.pixels, 0, width * height); bg.updatePixels(); for (int i = 0; i < NUM_WAVES; i++) { wave[i].update(); wave[i].composite(waveBackground.pixels); } waveBackground.updatePixels(); }