/**
* Keys:
* 1: water
2: land
3: erase
4: change color
5: liquify
6: make water white
7: clear
*/
FPS fps = new FPS();
int water[] = new int[10];
int waterCount = 0;
int waterpixels[];
int pixelids[];
boolean sleepers[];
int waterColor = 0xFF0000FF;
int alphaColor = 0xFF000000;
int bgColor = 0x00C8C8FF;
int bgColor2 = 0xFFC8C8FF;
int toolbarColor = 0xFF8080A0;
Random rand;
PImage waterImage;
final int WATER = 0;
final int LAND = 1;
final int ERASE = 2;
int inputMode = WATER;
void setup() {
Dimension d = getSize();
size(400,400,P3D);
hint(DISABLE_TEXT_SMOOTH);
textFont(loadFont("Verdana-9.vlw"));
loadPixels();
waterpixels = pixels;
// waterpixels = new int[width*height];
// waterImage = new PImage(waterpixels,width,height,RGBA);
for (int i=0; i>1,height>>1);
// textCenter("by Marcello Bastea-Forte",width>>1,(height>>1)+10);
}
void textCenter(String s, int x, int y) {
textAlign(LEFT);
text(s, x, y);
}
void drawColor() {
fill(waterColor);
stroke(bgColor);
rect(1,1,7,7);
}
String modeText = "";
void drawMode() {
textAlign(LEFT);
fill(toolbarColor);
text(modeText,10,9);
fill(0xFFFFFFFF);
switch (inputMode) {
case WATER:
modeText = "Add Water";
break;
case LAND:
modeText = "Add Land";
break;
case ERASE:
modeText = "Erase";
break;
}
text(modeText,10,9);
}
String particleCount = "";
void drawParticleCount() {
textAlign(RIGHT);
fill(toolbarColor);
noStroke();
int w=(particleCount.length())*7;
rect(width-w-2,0,w,9);
particleCount = waterCount+"/"+water.length+" - "+asleep+" sleeping - "+fps.fps+"fps";
fill(0xFFFFFFFF);
text(particleCount,width-2,8);
}
void keyReleased() {
switch (key) {
case '1':
inputMode = WATER;
drawMode();
break;
case '2':
inputMode = LAND;
drawMode();
break;
case '3':
inputMode = ERASE;
drawMode();
break;
case '4':
waterColor = alphaColor|rand.nextInt();
drawColor();
break;
case '5':
for (int i=10*width; i=0;) {
waterpixels[water[i]]=0xFFFFFFFF;
}
break;
case '7':
for (int i=waterpixels.length; --i>=10*width;) {
waterpixels[i] = bgColor;
pixelids[i] = 0;
sleepers[i] = false;
}
asleep = 0;
waterCount = 0;
break;
}
}
void draw() {
// background(200);
if (mousePressed) {
int dx=pmouseX-mouseX;
int dy=pmouseY-mouseY;
if (dx==0&&dy==0)
drawPoint(mouseX,mouseY);
else {
double x=mouseX,y=mouseY;
double units=Math.max(Math.abs(dx),Math.abs(dy));
double hunit=dx/units;
double vunit=dy/units;
for (int ii=(int)units; --ii>=0;) {
x+=hunit;
y+=vunit;
drawPoint((int)x,(int)y);
}
}
}
moveWater();
fps.frame();
drawParticleCount();
// image(waterImage,0,0);
}
void drawPoint(int xx, int yy) {
for (int y=-2;y<=2;y++)
for (int x=-2;x<=2;x++) {
switch (inputMode) {
case WATER:
addWater(xx+x,yy+y,waterColor);
break;
case LAND:
addLand(xx+x,yy+y,0xFFB77E39);
break;
case ERASE:
erase(xx+x,yy+y);
break;
}
}
}
void moveWater() {
int x,y,pos,c;
boolean l,r;
for (int i=0; i0) {
wake(x-1,y);
wake(x,y-1);
x++;
}
else continue; // nothing moved
}
else if (r) {
if (rand.nextInt(5)>0) {
wake(x+1,y);
wake(x,y-1);
x--;
}
else continue; // nothing moved
}
else {
int dx = rand.nextInt(3)-1;
if (dx==0) continue; // nothing moved
x += dx;
wake(x,y-1);
}
}
else { /* nothing solid beneath */
wake(x-1,y);
wake(x+1,y);
wake(x,y-1);
y++;
}
// clear old square color and pixel id
waterpixels[pos] = bgColor;
// waterpixels[pos] = 0xFF808000;
pixelids[pos] = 0;
// calculate new square
pos = x+y*width;
if (sleepers[pos]) {
println("Trying to overwrite sleeper ["+x+","+y+"]");
c = 0xFFFF0000;
}
if (pixelids[pos]>0) {
println("Trying to overwrite water ["+x+","+y+"]");
c = 0xFF000000;
}
// update water's position
water[i] = pos;
// update color and pixel id
waterpixels[pos] = c;
pixelids[pos] = i+1;
}
}
final private int mix(int c1, int c2) {
return alphaColor | ((((c1&0xFEFEFF))+((c2&0xFEFEFF)))>>1);
}
final private int mixColor(int x, int y) {
int c=waterpixels[x+y*width];
if (true)
return c;
if (rand.nextInt(5)>0) return c;
/*
switch (rand.nextInt(4)) {
case 0: if (liquid(x,y-1)) waterpixels[x+(y-1)*width]=c=mix(c,waterpixels[x+(y-1)*width]); break;
case 1: if (liquid(x,y+1)) waterpixels[x+(y+1)*width]=c=mix(c,waterpixels[x+(y+1)*width]); break;
case 2: if (liquid(x+1,y)) waterpixels[x+1+y*width]=c=mix(c,waterpixels[x+1+y*width]); break;
case 3: if (liquid(x-1,y)) waterpixels[x-1+y*width]=c=mix(c,waterpixels[x-1+y*width]); break;
}
*/
if (liquid(x,y-1)) waterpixels[x+(y-1)*width]=c=mix(c,waterpixels[x+(y-1)*width]);
if (liquid(x,y+1)) waterpixels[x+(y+1)*width]=c=mix(c,waterpixels[x+(y+1)*width]);
if (liquid(x+1,y)) waterpixels[x+1+y*width]=c=mix(c,waterpixels[x+1+y*width]);
if (liquid(x-1,y)) waterpixels[x-1+y*width]=c=mix(c,waterpixels[x-1+y*width]);
waterpixels[x+y*width] = c;
return c;
}
final private boolean liquid(int x, int y) {
if (x<0||y<10||x>=width||y>=height) return false;
int pos = x+y*width;
return pixelids[pos]>0;
}
final private boolean solid(int x, int y) {
if (x<0||y<10||x>=width||y>=height) return true;
int pos = x+y*width;
return ((0xFF000000&waterpixels[pos]) != 0) || pixelids[pos]>0;
}
void addWater(int x, int y, int c) {
// Don't overwrite land
if (solid(x,y)) return;
// If square is already water, just change its color
int pos = x+y*width;
if (liquid(x,y)) {
waterpixels[pos]=c;
return;
}
// otherwise, add it!
addWater(pos,c);
}
void addWater(int pos, int c) {
// Make sure there is enough room to add water
if (waterCount >= water.length) {
int t[] = water;
water = new int[t.length*2];
System.arraycopy(t,0,water,0,t.length);
t = null;
}
// add water at very end and increment counter
water[waterCount++] = pos;
// set color
waterpixels[pos] = c;
// set pixel id (this is +1 from the actual id, but we already did waterCount++ above)
pixelids[pos] = waterCount;
// not asleep
sleepers[pos] = false;
}
int asleep=0;
void sleep(int x, int y) {
if (x<0 || y<10 || x>=width || y>=height) return;
// get position
int pos = x+y*width;
// get water id
int id = pixelids[pos]-1;
pixelids[pos] = 0;
// continue if there is no water id
if (id < 0 || id>=waterCount) return;
// set water id to zero
sleepers[pos] = true;
//waterpixels[pos] = 0xFF000080;
pixelids[pos] = 0;
asleep++;
// decrement water count (this deletes water)
waterCount--;
// copy last water and replace the deleted water id with that
if (id!=waterCount) {
water[id] = water[waterCount];
water[waterCount] = 0;
pixelids[water[id]] = id+1;
}
}
void wake(int x, int y) {
if (x<0 || y<10 || x>=width || y>=height) return;
int pos = x+y*width;
if (!sleepers[pos]) return;
if (asleep<=0) {
println("Trying to wake up more than we've put to sleep!");
return;
}
asleep--;
sleepers[pos] = false;
// Make sure there is enough room to add water
if (waterCount >= water.length) {
int t[] = water;
water = new int[t.length*2];
System.arraycopy(t,0,water,0,t.length);
t = null;
}
water[waterCount++] = pos;
pixelids[pos] = waterCount;
//waterpixels[pos] = 0xFF0000FF;
}
void erase(int x, int y) {
if (x<0 || y<10 || x>=width || y>=height) return;
// calculate position
int pos = x+y*width;
// clear color
waterpixels[pos] = bgColor;
// get id and check if the cell has water
int id = pixelids[pos]-1;
if (id>=0 && id