"Smooth paintbrush"

edited April 2017 in Share Your Work

This was supposed to be a celluar automata kind of thing but it was blinking so annoyingly.
Got a smoother turbulence thing going and added random painting to it which looks pretty cool in motion.

paint

https://youtube.com/watch?v=cd-ZNymt6Ko&feature=youtu.be

newer video -> https://youtube.com/watch?v=cbCyq5RMXLk

leftclick, paint, rightclick erase

Update2,

Faster version any key changes "rule"

int button;
int speed;
int paint; 
int xyz;
int vdit;
int[] field;
int[] b;
boolean closerThan(int distance,int x0,int y0){
  int dx = x0-mouseX; dx*=dx;
  int dy = y0-mouseY; dy*=dy;
return dx+dy<distance;}
int sts (int l){ return ((l%4==0)?0:2)*((floor(l/4)%2==1)?-1:1);}
int[] pbox(int n, int layer){
int px,py,xt,yt; xt=yt=0;
  px=(layer%2==0)?0:1;
  py=(layer<=1)?0:1;
  if(n<=7){ xt=px==0?1:-1;}
  else    { yt=py==0?1:-1;}
  xt += sts(n);
  yt += sts(n+2);
  return new int[]{xt,yt};
} 
int[] pboxresult = new int[2];
int[][] overview = { 
{ 1,2,3,2,3,0,3,-2, 1,-2,-1,-2,-1,0,-1,2,0,3,2,3,2, 1,2,-1,0,-1,-2,-1,-2, 1,-2,3},
{-1,2,1,2,1,0,1,-2,-1,-2,-3,-2,-3,0,-3,2,0,3,2,3,2, 1,2,-1,0,-1,-2,-1,-2, 1,-2,3},
{ 1,2,3,2,3,0,3,-2, 1,-2,-1,-2,-1,0,-1,2,0,1,2,1,2,-1,2,-3,0,-3,-2,-3,-2,-1,-2,1},
{-1,2,1,2,1,0,1,-2,-1,-2,-3,-2,-3,0,-3,2,0,1,2,1,2,-1,2,-3,0,-3,-2,-3,-2,-1,-2,1}
};

int[][] compare = new int[4][32];
int[][] transform = new int[4][32];
long RULE;
long randomlong(){
  long result = floor(random(0,65536));
  for(int i=0;i<3;i++){
  result<<= 24;
  result+=floor(random(0,16777216));
  }
  return result;
}
void compare_update(){
for(int i=0; i<4; i++){
for(int j=0; j<16; j++){
compare[i][j*2  ] = overview[i][j*2  ]; // map(overview[i][j*2  ],-width,width,-1,1);
compare[i][j*2+1] = overview[i][j*2+1]; // map( -height,height,-1,1);
}}}
void transform_update(){
for(int i=0; i<4; i++){
RULE = randomlong();
for(int j=0; j<16; j++){
pboxresult = pbox(int((RULE>>(j*4))&15),i);
transform[i][j*2  ]=pboxresult[0];
transform[i][j*2+1]=pboxresult[1];
}}}

void setup() {
  size(384, 384);
  xyz=width*height;
  field=new int[xyz];
  b=new int[xyz];
  loadPixels();
  compare_update();
  new_rule();
}

void keyPressed(){
  new_rule();
}
void new_rule(){
  transform_update();
}
int frag(int p){
  int x=p%width;
  int y=p/width;
  int comp=0;
  int mine;

  if(mousePressed && closerThan(speed,x,y)){ 
    return paint;
} else { 
  int mylayer = (x%2==0?0:1)+(y%2==0?0:2);
  mine = b[p];
  for(int i =0; i<15; i++){
  comp +=((b[((x+compare[mylayer][i*2]+(y+compare[mylayer][i*2+1])*width)+xyz)%xyz]<mine)?1:0);
  }
  return b[((x+transform[mylayer][comp*2]+(y+transform[mylayer][comp*2+1])*width)+xyz)%xyz];
}
}
void worker_a(){
  for(int p=0; p<xyz; p++){
    b[p]=pixels[p]=field[p];
  }
}
void worker_b(){
  for(int p=0; p<xyz; p++){
    field[p]=frag(p);
  }
}
void draw(){
  println(frameRate);
  if(mousePressed){
  if( mouseButton == LEFT ){
    button=1;
    paint=floor(random(#000000,#ffffff));
  } else{button =2; paint=#fffffe;}
}
  else { button = 0; }
  speed = int(sq(mouseX-pmouseX)+sq(mouseY-pmouseY)); // intentionally not using sqrt()
  rect(0,0,width,height);
  thread("worker_a");
  thread("worker_b");
  updatePixels();
}

Object oriented version

int paint;
int dis;
int speed;
int rulecounter;
int smooth = 1;
int xyz=256;
field g;
int randomcolor(){return floor(random(#000000,#ffffff));}
void setup(){size(256,256,P2D);g = new field();loadPixels();}
void draw() {
    speed=floor(dist(pmouseX,pmouseY,mouseX,mouseY));
    if(mousePressed){
      if(mouseButton==LEFT) {
        paint = randomcolor();
        } else { paint = #ffffff; }
    }
  g.update();
  g.display();
  if(rulecounter++%100==0){g.randomrule();}
}
class field {
  subdivision[][] rid;
  long[] RULE;
  field() {
      RULE = new long[4];
      randomrule();
      int[] VAL;
      rid = new subdivision[xyz][xyz];
      for (int y = 0 ; y < xyz; y++) {
      for (int x = 0 ; x < xyz; x++) {
        VAL = new int []{#ffffff,#ffffff,#ffffff,#ffffff};
        rid[x][y] = new subdivision(x,y,VAL,RULE);
      }}
      for (int y = 0 ; y < xyz; y++) {
      for (int x = 0 ; x < xyz; x++) {
        rid[x][y].set_neighbours(this.rid);
    }}
  }
long randomlong(){
  long result = floor(random(0,65536)); 
  for(int i=0;i<3;i++){
  result<<= 24;
  result+=floor(random(0,16777216));
  }
  return result;
}
void randomrule(){
  RULE[0] = randomlong();
  RULE[1] = randomlong();
  RULE[2] = randomlong();
  RULE[3] = randomlong();
}
void update(){
  for (int y=0;y<xyz;y++){
  for (int x=0;x<xyz;x++){
    rid[x][y].update_pixels();
  }}
}
void display(){
  updatePixels();
  for (int y=0;y<xyz;y++){
  for (int x=0;x<xyz;x++){
      rid[x][y].buffer();
  }}
}
}
class subdivision{
  long [] rule;
  int [] ra; // results array
  int [] val; // value array
  int x,y; // coordinate of the pixel
  int xy; // x,y in one dimensional framebuffer
  int [][] neighbours;
  subdivision(int X, int Y,    int[]VAL, long[]RULE){
                x=X;   y=Y;     val=VAL;  rule=RULE;
                xy = x+xyz*y;
                neighbours = new int [8][4];
                ra = new int [4];
  }
  void set_neighbours(subdivision[][] rid){
    int x1,x3,y1,y3;
    for ( int i=0; i < 4; i++) {
      x1=(x+1)%xyz; x3=(x+xyz-1)%xyz; // 3 is -1 as it "wraps around"
      y1=(y+1)%xyz; y3=(y+xyz-1)%xyz;
      // surrounding pixels clockwise
      neighbours[ 0] = rid[x1][y3].val;
      neighbours[ 1] = rid[x1][ y].val;
      neighbours[ 2] = rid[x1][y1].val;
      neighbours[ 3] = rid[ x][y1].val;
      neighbours[ 4] = rid[x3][y1].val;
      neighbours[ 5] = rid[x3][ y].val;
      neighbours[ 6] = rid[x3][y3].val;
      neighbours[ 7] = rid[ x][y3].val;  
    }
  }

  /* Thanks to u/ErasmusDarwin */
  int blackbox(long n,long rule){return int((rule>>(n*4))&15);}

  int pixel(int foo, int bar) { 
  if (smooth <= 0){return foo;} else if(smooth >= 8){return bar;} else{
  int r,g,b;
  r = ( ( (foo >> 16 & 0xFF) * ((1 << smooth) -1) + (bar >> 16 & 0xFF) ) >> smooth ) << 16;
  g = ( ( (foo >>  8 & 0xFF) * ((1 << smooth) -1) + (bar >>  8 & 0xFF) ) >> smooth ) << 8;
  b = ( ( (foo       & 0xFF) * ((1 << smooth) -1) + (bar       & 0xFF) ) >> smooth );
  return r+g+b;
  }
  }

  int merge(){
  int r,g,b;
  r = (((ra[0] >> 16 & 0xFF) + (ra[1] >> 16 & 0xFF) + (ra[2] >> 16 & 0xFF) + (ra[3] >> 16 & 0xFF)) >> 2) << 16;
  g = (((ra[0] >>  8 & 0xFF) + (ra[1] >>  8 & 0xFF) + (ra[2] >>  8 & 0xFF) + (ra[3] >>  8 & 0xFF)) >> 2) << 8;
  b = ((ra[0]        & 0xFF) + (ra[1]       & 0xFF) + (ra[2]       & 0xFF) + (ra[3]       & 0xFF)) >> 2;
  return #000000+r+g+b;
  }
  void update_pixels() {
    dis=floor(dist(mouseX,mouseY,x,y));
    int c;   // comparission
    int t;  // transformation
    int r; // result
    int top, bottom, layer; // 
    for (int l=0; l<4; l++){
      if(mousePressed) {
        smooth = max(0,min(8,dis >> 6));
        } else {
        smooth=0;
        }
      if(mousePressed && dis<1+speed) {
        r = paint;
        } else {
        top = (l+1)%4; bottom=(l+3)%4;
        c=0;
        for (int n=0; n<8; n++){
        if ( val[l] > neighbours[ n][top] ) {c++;}
        if ( val[l] > neighbours[ n][bottom] ) {c++;}
        }
        t=blackbox(c,rule[l]);
        if (t<=7){ layer = top; } else { t-=8; layer=bottom; }
        r=neighbours[t][layer];
        }
      ra[l]=pixel(r,val[l]);
    }
    pixels[xy] = merge();
  }
  void buffer() {
    for (int l=0; l<4; l++) {
      val[l]=ra[l];
    }
  }
}

Original version

/* Thanks to u/ErasmusDarwin for map function*/
//int rule_map(int n,int rule){return(rule>>(n*2))&3;} 4^4, rules 2^8
//int rule_map(int n,int rule){return int((rule>>(n*3))&7);} 8^8, rules 2^24
int rule_map(long n,long rule){return int((rule>>(n*4))&15);} // 16^16, 2^64 rules
void rla(){
  for(int i=0;i<4;i++){
  rule[i]=randomlong();
  }
}
long randomlong(){
  long result = floor(random(0,65536)); 
  for(int i=0;i<3;i++){
  result<<= 24;
  result+=floor(random(0,16777216));
  }
  return result;
}
int rlac,smooth = 1;
class gray { gray(){}
int pixel(int[]ca) { 
  if (smooth == 0){return ca[3];} else{
  int r,g,b;
  r = ( ( (ca[3] >> 16 & 0xFF) * ((1 << smooth) -1) + (ca[0] >> 16 & 0xFF) ) >> smooth ) << 16;
  g = ( ( (ca[3] >>  8 & 0xFF) * ((1 << smooth) -1) + (ca[0] >>  8 & 0xFF) ) >> smooth ) << 8;
  b = ( ( (ca[3]       & 0xFF) * ((1 << smooth) -1) + (ca[0]       & 0xFF) ) >> smooth );
  return r+g+b;
  }
  }
int merge(int[]ca) {
  int r,g,b;
  r = (((ca[0] >> 16 & 0xFF) + (ca[1] >> 16 & 0xFF) + (ca[2] >> 16 & 0xFF) + (ca[3] >> 16 & 0xFF)) >> 2) << 16;
  g = (((ca[0] >>  8 & 0xFF) + (ca[1] >>  8 & 0xFF) + (ca[2] >>  8 & 0xFF) + (ca[3] >>  8 & 0xFF)) >> 2) << 8;
  b = ((ca[0]       & 0xFF) + (ca[1]       & 0xFF) + (ca[2]       & 0xFF) + (ca[3]       & 0xFF)) >> 2;
  return r+g+b;
  }
}
gray gs = new gray();
int randomcolor(){return floor(random(0x0,0xffffff));}
int paint = 0x0;
int swap,cc,xyz=256;
long[] rule = new long [4];
int[][][][] fields = new int[2][4][xyz][xyz];
int[]ca=new int[4];
int[]aa=new int[4];
void clear() {
  for(int b=0;b<2;b++){
    for(int d=0;d<4;d++){
      for (int x=0;x < xyz; x++) {
        for (int y = 0; y < xyz; y++) {
          fields[b][d][x][y] = #ffffff;}}}}}

int algorithm(int d,int x0,int y0){
  int dis=floor(dist(mouseX,mouseY,x0,y0));
  int speed=floor(dist(pmouseX,pmouseY,mouseX,mouseY));
  int [][]n1=fields[swap][(d+4+1)%4]; 
  int [][]n2=fields[swap][(d+4+3)%4];
  int m=fields[swap][d][x0][y0];
  aa[0]=aa[1]=aa[2]=aa[3]=m & 0xfffffe;
  if(mousePressed){
    if(dis<1+speed){if(mouseButton==LEFT){return paint;}else{return 0xffffff;}}
    smooth=max(0,min(8,dis >> 6));
                  } else{smooth=0;}

  int t=0*0;
  int y1=(y0+1)%xyz,y3=(y0+xyz-1)%xyz,
      x1=(x0+1)%xyz,x3=(x0+xyz-1)%xyz;
  int c = max(0,(((m>n1[x0][y0])?1:0)+
                 ((m>n1[x0][y1])?1:0)+
                 ((m>n1[x0][y3])?1:0)+
                 ((m>n1[x1][y0])?1:0)+
                 ((m>n1[x3][y0])?1:0)+
                 ((m>n2[x0][y0])?1:0)+
                 ((m>n2[x0][y1])?1:0)+
                 ((m>n2[x0][y3])?1:0)+
                 ((m>n2[x1][y0])?1:0)+
                 ((m>n2[x3][y0])?1:0))-1);
       switch((rule_map(c,rule[d]))%16){
       case 0:t= n1[x0][y1];break;
       case 1:t= n1[x0][y3];break;
       case 2:t= n1[x1][y0];break;
       case 3:t= n1[x3][y0];break;
       case 4:t= n1[x1][y1];break;
       case 5:t= n1[x3][y3];break;
       case 6:t= n1[x3][y1];break;
       case 7:t= n1[x1][y3];break;
       case 8:t= n2[x0][y1];break;
       case 9:t= n2[x0][y3];break;
       case 10:t= n2[x1][y0];break;
       case 11:t= n2[x3][y0];break;
       case 12:t= n2[x1][y1];break;
       case 13:t= n2[x3][y3];break;
       case 14:t= n2[x3][y1];break;
       case 15:t= n2[x1][y3];break;
       default:break;}
       aa[3]=t;
       return gs.pixel(aa);
   }
void setup(){size(256,256,P2D);rla();clear();loadPixels();}
void draw() { for (int x=0;x<xyz;x++){
              for (int y=0;y<xyz;y++){
              for (int d=0;d<4;d++){
              fields[(swap+1)%2][d][x][y]=ca[d]=algorithm(d,x,y);
              if(d==3){pixels[x+xyz*y]=gs.merge(ca);}}}
            } updatePixels(); paint = randomcolor();
              if(swap==0){swap=1;}else{swap=0;}
              if(rlac++%100==0){rla();}
            }

Comments

  • Shame about the blinking but as you say, some nice patterns develop. =D>

Sign In or Register to comment.