color hard = color(255, 76, 70); color snow = color(255, 245, 167); color black = color(0, 0, 0); int brushSize; boolean snowing; boolean bottomVortex; int snowDensity; ArrayList vortexes; ArrayList generators; void setup() { size(700, 500, P2D); background(0, 0, 0); snowing = false; bottomVortex = false; snowDensity = 0; vortexes = new ArrayList(); generators = new ArrayList(); } void draw() { if (mousePressed) { noStroke(); if (mouseButton == LEFT) { brushSize = 4; stroke(hard); } else { brushSize = 8; stroke (black); } strokeWeight(brushSize); line(pmouseX, pmouseY, mouseX, mouseY); } ////////////////////////////////////////// // Make random snow if (snowing) { stroke (snow); strokeWeight(1); for (int x = 0; x < width; x++) { if (random(1000) > 990 + snowDensity) { point(x, 1); } } } // Make random snow ////////////////////////////////////////// ////////////////////////////////////////// // Draw vortexes for (int i = 0; i < vortexes.size(); i++) { Vortex v = (Vortex) vortexes.get(i); v.update(); } // Draw vortexes ////////////////////////////////////////// ////////////////////////////////////////// // Draw generators for (int i = 0; i < generators.size(); i++) { Generator g = (Generator) generators.get(i); g.update(); } // Draw generators ////////////////////////////////////////// if (bottomVortex) { DrawBottomVortex(); } loadPixels(); for(int y = height - 1; y >= 0; y--) { for(int x = width - 1; x >= 0; x--) { if (y < height - 1) { if (GetPixel(x, y) == snow) { // Move the pixel down switch (GetDownPosition(x, y)) { case 0: // No movement DOWN available, then try special cases sideways switch (GetSidesPosition(x, y)) { case 2: // right MovePixel(x, y, x + 1, y); break; case 3: // left MovePixel(x, y, x - 1, y); break; default: // No room for pixel to move in either direction break; } break; case 1: // Down MovePixel(x, y, x, y + 1); break; case 2: // Down right MovePixel(x, y, x + 1, y + 1); break; case 3: // Down left MovePixel(x, y, x - 1, y + 1); break; } } } } } updatePixels(); } void keyPressed() { // Toggle snow if (key == ' ') { snowing = !snowing; } // Reset background if (keyCode == BACKSPACE || keyCode == DELETE) { background(0, 0, 0); vortexes.clear(); generators.clear(); } // Increase snow density if (key == '+') { snowDensity -= 10; } //decrease snow density if (key == '-') { if (snowDensity < 10) { snowDensity += 10; } } // Throw in a small vortex if (key == 'v') { vortexes.add(new Vortex(mouseX, mouseY, 16)); } // Throw in a big vortex if (key == 'V') { vortexes.add(new Vortex(mouseX, mouseY, 32)); } // Throw in a small generator if (key == 'g') { generators.add(new Generator(mouseX, mouseY, 1)); } // Throw in a big generator if (key == 'G') { generators.add(new Generator(mouseX, mouseY, 5)); } // Randomize spots if (key == 'x') { RandomizeSpots(); } // Bottom vortex ("Infinite mode") if (key == 'i') { bottomVortex = !bottomVortex; } } int GetSidesPosition(int x, int y) { // Checks what pixel is available to the sides of a certain pixel if (x >= (width - 2) || x <= 2) { // We can't perform this calculation, since the pixel is right on the edge // of the screen. return 0; } if ( GetPixel(x + 1, y) == black && // blank right GetPixel(x + 1, y - 1) == black && // blank top right GetPixel(x, y - 1) == black && // blank top GetPixel(x - 1, y) == black && // blank up left GetPixel(x - 1, y - 1) == snow && // snow left GetPixel(x - 2, y - 1) == snow // snow up left x 2 ) { // The pixel to the right is available return 2; } if ( GetPixel(x - 1, y) == black && // blank left GetPixel(x - 1, y - 1) == black && // blank top left GetPixel(x, y - 1) == black && // blank top GetPixel(x + 1, y) == black && // blank up right GetPixel(x + 1, y - 1) == snow && // snow right GetPixel(x + 2, y - 1) == snow // snow up right x 2 ) { // The pixel to the right is available return 3; } if ( GetPixel(x + 1, y - 1) == black && // blank top right GetPixel(x, y - 1) == black && // blank top GetPixel(x + 1, y) == black && // blank right GetPixel(x - 1, y - 1) == snow && // snow left GetPixel(x - 1, y) == snow // snow up left ) { // The pixel to the right is available return 2; } if ( GetPixel(x - 1, y - 1) == black && // blank top left GetPixel(x, y - 1) == black && // blank top GetPixel(x - 1, y) == black && // blank left GetPixel(x + 1, y - 1) == snow && // snow right GetPixel(x + 1, y) == snow // snow up right ) { // The pixel to the left is available return 3; } return 0; } int GetDownPosition(int x, int y) { // Checks what pixel is available under a certain pixel boolean one = false; boolean two = false; boolean three = false; if (GetPixel(x, y + 1) == black) { // The immediate down pixel is available one = true; } if (x < (width - 1) && GetPixel(x + 1, y + 1) == black) { // The pixel down to the right is available two = true; } if (x > 0 && GetPixel(x - 1, y + 1) == black) { // The pixel down to the left is available three = true; } ////////////////////////////////////// // The particle is still flying if (one && two && three) { int r = (int)random(2, 51); if (r > 3) { // go down return 1; } else { // go diagonal return r; } } ////////////////////////////////////// // The particle has hit another particle if (!one && two && three) { return (int) random(2, 4); } if (one && !two && three) { int r = (int)random(1, 3); if (r == 2) { return 3; } else { return 1; } } if (one && two && !three) { int r = (int)random(1, 3); if (r == 2) { return 2; } else { return 1; } } if (one && !two && !three) { return 1; } if (!one && two && !three) { return 2; } if (!one && !two && three) { return 3; } if (!one && !two && !three) { return 0; } return 0; } void MovePixel(int sourcex, int sourcey, int targetx, int targety) { SetPixel(sourcex, sourcey, black); SetPixel(targetx, targety, snow); } int GetPixel(int x, int y) { return pixels[((y * width) + x)]; } void SetPixel(int x, int y, color col) { pixels[((y * width) + x)] = col; } void DrawBottomVortex() { stroke(black); strokeWeight(1); line (0, height - 1, width, height - 1); } void RandomizeSpots() { int spotWidth = 60; stroke(hard); strokeWeight(2); for (int i = 1; i <= 50; i++) { float x = random(1, width - spotWidth); float y = random(1, height - spotWidth); float level = random(-spotWidth, spotWidth); line(x - (spotWidth / 2), y, x + (spotWidth / 2), y + level); } } class Vortex { // A vortex sucks up snow int x, y, w; Vortex (int newX, int newY, int newWidth) { x = newX; y = newY; w = newWidth; } void update() { noStroke(); fill(black); ellipse(x, y, w, w); } } class Generator { // A Generator generates snow int x, y, w; Generator (int newX, int newY, int newW) { x = newX; y = newY; w = newW; } void update() { stroke(snow); strokeWeight(1); for (int i = 1; i <= w; i++) { if ((int)random(1, 3) == 1) { point(x + i, y); } } } }