/* * "Falling Sand"-style Water Simulation * (c) 2009 Janis Elsts * * More info : http://w-shadow.com/blog/2009/09/29/falling-sand-style-water-simulation/ */ import processing.opengl.*; //Camera position and movement stuff PVector camera_pos, camera_dir; float camera_speed = 3.0; final float MAX_ZOOM = 20.0; final float MIN_ZOOM = 0.1; float zoom_level = 1.0, zoom_speed = 0.02, zoom_dir = 0.0; PVector translationVect; PVector worldPos; //The world //Simulation stuff boolean paused = false; final byte clearUpdateMask = byte(0x7F); //0111 1111 final byte staticTile = byte(0x40); //0100 0000 final byte clearAllMask = byte( clearUpdateMask & (~staticTile) ); //Tile types final byte air = byte(0 | staticTile); final byte ground = byte(1 | staticTile); final byte water = 2; final byte stillwater = byte(water | staticTile); final byte faucet = 4; final byte pointer = 50; String[] tileNames; //World data and dimensions final int WORLD_WIDTH = 256; final int WORLD_HEIGHT = 256; SimulationWorld theWorld; //Drawing the world final float TILE_SIZE = 20; //pixels color[] tileColors; int drawAreaSize = 0; PFont font; //Drawing *on* the world byte selectedTileType = water; void setup(){ size(640, 480, OPENGL); background( 255, 255, 255 ); smooth(); initWheelListener(); //Listen for mousewheel events //Initialize the camera camera_pos = new PVector(0, 0); camera_dir = new PVector(0, 0); translationVect = new PVector(0, 0); worldPos = new PVector(0,0); resetCameraPos(); //Initialize tile co;ors tileColors = new color[127]; tileColors[air] = color(255, 255, 255); tileColors[ground] = color(0xeb, 0xc4, 0x29); tileColors[water] = color(72, 124, 255); tileColors[stillwater] = color(72, 124, 200); tileColors[faucet] = color(150, 200, 255); tileColors[pointer] = color(50, 250, 50); font = loadFont("ArialMT-36.vlw"); textFont(font, 20); tileNames = new String[127]; tileNames[air] = "Air"; tileNames[ground] = "Ground"; tileNames[water] = "Water"; tileNames[faucet] = "Faucet"; tileNames[pointer] = "Pointer"; //Create the simulation world theWorld = new SimulationWorld( WORLD_WIDTH, WORLD_HEIGHT ); theWorld.randomize(); } void draw(){ //Clear the screen background(255, 255, 255); //Move the camera camera_pos.add( PVector.mult(camera_dir, camera_speed) ); //Zoom zoom_level = zoom_level + zoom_dir * zoom_speed; zoom_level = constrain(zoom_level, MIN_ZOOM, MAX_ZOOM); //Calculate the translation vector translationVect.set( camera_pos ); translationVect.add( width/2/zoom_level, height/2/zoom_level, 0 ); //Transform the display to match the camera position pushMatrix(); scale( zoom_level ); translate( translationVect.x, translationVect.y ); //Calculate the location of the mouse pointer within the simulation world worldPos = screen2world( mouseX, mouseY ); int wx = ceil(constrain( worldPos.x, 1, theWorld.world_width )); int wy = ceil(constrain( worldPos.y, 1, theWorld.world_height )); //Edit the world if the mouse is pressed if ( mousePressed ){ if (mouseButton == LEFT){ //Replace the current tile with the selected tile type theWorld.setTile( wx, wy, byte(selectedTileType | theWorld.update_mask) ); } else if (mouseButton == RIGHT){ //Erase the current tile theWorld.setTile( wx, wy, air ); } } //Run the simulation if ( !paused ){ theWorld.stepSimulation(); } //Calculate the visible portion of the world (used for culling invisible tiles) PVector minVisiblePoint = screen2world(0, height); PVector maxVisiblePoint = screen2world(width, 0); //Draw the world theWorld.display( floor(minVisiblePoint.x), floor(minVisiblePoint.y), ceil(maxVisiblePoint.x), ceil(maxVisiblePoint.y) ); //Highlight the tile under the mouse pointer theWorld.drawTile( ceil(worldPos.x), ceil(worldPos.y), pointer ); popMatrix(); drawPanel(); } void drawPanel(){ rectMode(CORNER); fill( 240, 200, 100 ); stroke(0, 0, 0); rect(0, 0, width, 22); fill(0, 0, 0); textAlign(LEFT, CENTER); textFont(font, 16); text( "FallingWater " + (paused?"[P]":" ") + " [ " + str(round(frameRate)) + " FPS, Draw area : " + str(drawAreaSize) + " tiles, " + "Paint : " + tileNames[selectedTileType] + ", AT : " + str(theWorld.activeTiles)+ " ]", 4, 10); }