// MBALL_03
//
// metaballs reactive system
// click/drag to interact
//
// Seb Chevrel | <A HREF="http://www.seb.cc">www.seb.cc</A>
// ———————————————————————————————————————————————————————————————
int WIDTH=400;
int HEIGHT=400;
int NUMNODES=5;
boolean dragged=false;
float nodes[][]=new float[NUMNODES][6];
int mul=NUMNODES*100;
int R,G,B,OR,OG,OB;
float dx=0;
float dy=0;
float dragox=0;
float dragoy=0;
int dragindex=0;
float dragd=1000;
float fx=0;
float fy=0;
float d2=0;
float d=0;
void setup() {
size(WIDTH,HEIGHT);
noBackground();
for(int i=0;i<HEIGHT*WIDTH;i++) pixels[i]=0;
// init positions and radius
for(int i=0;i<NUMNODES;i++) {
nodes[i][0]=int(random(WIDTH));
nodes[i][1]=int(random(HEIGHT));
nodes[i][2]=random(200)+60; // radius
nodes[i][3]=0; // not used
nodes[i][4]=0; // vx
nodes[i][5]=0; // vy
}
}
void loop() {
// apply forces on system
for(int n1=0; n1<NUMNODES;n1++) {
for(int n2=n1+1; n2<NUMNODES; n2++) {
dx=nodes[n2][0]-nodes[n1][0];
dy=nodes[n2][1]-nodes[n1][1];
d2=dx*dx;
d2+=dy*dy;
d=sqrt(d2);
if(d>10) {
fx=dx/50 -dx*mul/d2; // attraction/repulsion
fy=dy/50 - dy*mul/d2;
nodes[n1][4]+=fx; nodes[n2][4]-=fx;
nodes[n1][5]+=fy; nodes[n2][5]-=fy;
}
}
}
// update positions, apply friction
for(int n=0; n<NUMNODES; n++) {
nodes[n][0]+=nodes[n][4];
nodes[n][1]+=nodes[n][5];
nodes[n][4]*=0.9;
nodes[n][5]*=0.9;
}
if(mousePressed) {
if(dragged==true) {
nodes[dragindex][0]=mouseX-dragox;
nodes[dragindex][1]=mouseY-dragoy;
nodes[dragindex][4]=0;
nodes[dragindex][5]=0;
}
else {
dragd=10000;
for(int n=0; n<NUMNODES; n++) {
dx=mouseX-nodes[n][0];
dy=mouseY-nodes[n][1];
if ((abs(dx)<nodes[n][2]) && (abs(dy)<nodes[n][2])) {
d=sqrt(dx*dx+dy*dy);
if (d<dragd) {
dragox=dx;
dragoy=dy;
dragged=true;
dragindex=n;
dragd=d;
}
}
}
}
}
else {
dragged=false;
}
// render canvas
for(int i=0;i<HEIGHT;i+=2) {
for(int j=0;j<WIDTH;j++) {
R=0;
for(int n=0; n<NUMNODES; n++) {
dx=j-nodes[n][0];
dy=i-nodes[n][1];
dx=dx*dx;
dy=dy*dy;
d2=dx+dy;
R+=int(nodes[n][2]*10000/d2);
}
//R=int(R/NUMNODES) ;
if (R>1000) {
R=0;
G=0;
B=0;
} else {
R=int(sqrt(R*60));
if (R>255) R=255;
G=R;
B=R;
}
OR=(pixels[i*WIDTH+j]>>16) & 255;
OG=(pixels[i*WIDTH+j]>>8) & 255;
OB=pixels[i*WIDTH+j] & 255;
R=(OR*3+R)>>2;
G=(OG*3+G)>>2;
B=(OB*3+B)>>2;
pixels[i*WIDTH+j]=(G<<8)+(R<<16)+B;
}
}
}