made with proce55ing


// 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;
    }
  }

}