My projects library #4! Gallery Megathread

#56 Color channels reduction


(random image I found on the web used as source)

Code
int clrs = 4; //end has clrs^3 colors, (1-1, 2-8, 3-27, 4-64, 5-125, 6-216,...)
PImage img;
void setup() {
  size(640,642);
  img = loadImage("house2.jpg");
}
void draw() {
  image(img,0,0); noLoop();
  loadPixels();
  for(int i = 0; i < width; i++) for(int j = 0; j < height*0.5; j++) {
    int in = i+j*width, off = floor(width*height*0.5);
    color base = pixels[in], chan = closest(base,clrs);
    pixels[in+off] = chan;
  }
  updatePixels();
}
color closest(color input, int colorChannels) {
  float r = round(map(red(input)  ,0,255,0,colorChannels));
  float g = round(map(green(input),0,255,0,colorChannels));
  float b = round(map(blue(input) ,0,255,0,colorChannels));
  float m = 255/colorChannels;
  return color(floor(r*m),floor(g*m),floor(b*m));
}

It is similar to #55, but it runs far faster. Instead of finding the closest color, it just maps the color to the closest one.

#57 Fractal animation

Code
int n = 3; //starting to show with a line; if line intercepts circle, it is shown
float r = 150, rm = 0.5, rot=0;
ArrayList<c> cs = new ArrayList<c>();
float lY = 0, lS = 1;
boolean lActive = false;
void setup() {
  size(600, 600);
  cs.add(new c(300, 300, r));
  for (int j = 0; j < 5; j++) for (int i = 0, m = cs.size(); i < m; i++) cs.get(i).dupe();
}
void draw() {
  background(0);
  rot = atan2(mouseX-300, mouseY-300);
  for (int i = 0; i < cs.size(); i++) cs.get(i).display();
  if(lActive) {
    lY+=lS;
    line(0,lY,width,lY);
    if(lY>height) lActive = false;
  }
}
void keyPressed() {
  if (key== ' ') {
    lActive = true;
    lY = 0;
  }
}

class c {
  float x, y, r;
  boolean canDupe = true;
  c(float x_, float y_, float r_) {
    x = x_; 
    y = y_; 
    r = r_;
  }
  void dupe() {
    if (canDupe) for (float i = 0, a = TWO_PI/n; i < n; i++) cs.add(new c(x+cos(a*i)*r, y+sin(a*i)*r, r*rm));
    canDupe = false;
  }
  void display() {
    stroke(255); 
    noFill();
    if (lActive == false || lY>y-r) circle(x, y, r*2);
  }
}

This is a slight modification to a previous project (can’t remember which one), but the main difference is that you can trigger an event, where a line will move down the screen. All of the circles that are ‘above’ the line (even if just the outline), it will display it.

1 Like

#58 Twin spinners (bad name : P)

Code
float x1=200, y1=200, rad=50, dir = 0, dr = 10;
float s = PI*0.03;
boolean o = false;
ArrayList<PVector> p1 = new ArrayList<PVector>(), p2 = new ArrayList<PVector>();
void setup() {
  size(600,600);
}
void draw() {
  background(0); stroke(255);
  //for(int i = 0; i < p1.size()-1; i++) line(p1.get(i).x,p1.get(i).y,p1.get(i+1).x,p1.get(i+1).y);
  for(int i = 0; i < p2.size()-1; i++) line(p2.get(i).x,p2.get(i).y,p2.get(i+1).x,p2.get(i+1).y);
  
  dir+=s*(o? 1:-1);
  float px = x1+cos(dir)*rad;
  float py = y1+sin(dir)*rad;
  line(x1,y1,px,py);
  noStroke();
  fill((o? color(255,0,0) : color(0,255,0)));
  circle(x1,y1,dr*2);
  fill((!o? color(255,0,0) : color(0,255,0)));
  circle(px, py,dr*2);
  //if(o||!o) p1.add(new PVector(x1,y1));
  //else 
  p2.add(new PVector(px,py));
}

void mousePressed() {
  o=!o;
  float px = x1+cos(dir)*rad;
  float py = y1+sin(dir)*rad;
  float d = atan2(y1-py,x1-px);
  x1 = px;
  y1 = py;
  dir = d;
}
1 Like

#59 Simple memory card game
Alternative names: Mix-n-match, Concentration, Memory, Matching cards,…

Code
int w = 4, h = 4, scl = 150, buffer=5;
card c[][] = new card[w][h];
int s1 = -1, s2 = -1, state = 0;
void setup() {
  size(600, 600);
  for (int i = 0; i < w; i++) for (int j = 0; j < h; j++) {
    c[i][j] = new card(i, j, floor((i+j*w)/2));
  }
  shuffleBoard(1000);
}
void draw() {
  background(0);
  for (int i = 0; i < w; i++) for (int j = 0; j < h; j++) {
    c[i][j].display( (s1==i+j*w || s2==i+j*w), (s1 == i+j*w? #00FF00 : (s2 == i+j*w? #0000FF : #FFFFFF)) );
  }
}
void mousePressed() {
  int p = -1;
  for (int i = 0; i < w && i >= 0; i++) for (int j = 0; j < h && i >= 0; j++) {
    if (c[i][j].pressed(mouseX, mouseY)) {
      p = i+j*w;
      i = -2;
    }
  }
  if (state == 0 && p>=0) {
    s1 = p;
    s2 = -1;
    state++;
  } else if (state == 1) {
    if (p != s1) {
      s2 = p;
      state++;
    }
  } else if (state == 2) {
    state = 0;
    if (c[s1%w][floor(s1/w)].value == c[s2%w][floor(s2/w)].value) {
      c[s1%w][floor(s1/w)].active = false;
      c[s2%w][floor(s2/w)].active = false;
    } else {
      s1 = -1;
      s2 = -1;
    }
  }
}
void shuffleBoard(int times) {
  int temp;
  for (int i = 0; i < times; i++) {
    int x1=(int)random(w), y1=(int)random(h), x2=(int)random(w), y2=(int)random(h);
    temp = c[x1][y1].value;
    c[x1][y1].value = c[x2][y2].value;
    c[x2][y2].value = temp;
  }
}
class card {
  int x, y, value;
  boolean active;
  card(int X, int Y, int Value) {
    x = X;
    y = Y;
    value = Value;
    active = true;
  }
  void display(boolean show, color cl) {
    if (active) {
      fill(cl);
      square(x*scl+buffer, y*scl+buffer, scl-buffer*2);
      if (show) {
        fill(0);
        text(value, (x+0.5)*scl, (y+0.5)*scl);
      }
    }
  }
  boolean pressed(int mx, int my) {
    return(active && mx>x*scl+buffer && my>y*scl+buffer&&mx<(x+1)*scl-buffer&&my<(y+1)*scl-buffer);
  }
}

VERSION 2

Summary
int w = 4, h = 4, scl = 150, buffer=5;
card c[][] = new card[w][h];
int s1 = -1, s2 = -1, state = 0;
void setup() {
  size(600, 600);
  for (int i = 0; i < w; i++) for (int j = 0; j < h; j++) {
    c[i][j] = new card(i, j, floor((i+j*w)/2));
  }
  colorMode(HSB);
  textSize(scl*0.5);
  textAlign(3,3);
  shuffleBoard(1000);
}
void draw() {
  background(0);
  for (int i = 0; i < w; i++) for (int j = 0; j < h; j++) {
    c[i][j].display( (s1==i+j*w || s2==i+j*w));
  }
}
void mousePressed() {
  int p = -1;
  for (int i = 0; i < w && i >= 0; i++) for (int j = 0; j < h && i >= 0; j++) {
    if (c[i][j].pressed(mouseX, mouseY)) {
      p = i+j*w;
      i = -2;
    }
  }
  if (state == 0 && p>=0) {
    s1 = p;
    s2 = -1;
    state++;
  } else if (state == 1) {
    if (p != s1 && p != -1) {
      s2 = p;
      state++;
    }
  } else if (state == 2) {
    state = 0;
    if (c[s1%w][floor(s1/w)].value == c[s2%w][floor(s2/w)].value) {
      c[s1%w][floor(s1/w)].active = false;
      c[s2%w][floor(s2/w)].active = false;
    } else {
      s1 = -1;
      s2 = -1;
    }
  }
}
void shuffleBoard(int times) {
  int temp;
  for (int i = 0; i < times; i++) {
    int x1=(int)random(w), y1=(int)random(h), x2=(int)random(w), y2=(int)random(h);
    temp = c[x1][y1].value;
    c[x1][y1].value = c[x2][y2].value;
    c[x2][y2].value = temp;
  }
}
class card {
  int x, y, value;
  boolean active;
  card(int X, int Y, int Value) {
    x = X;
    y = Y;
    value = Value;
    active = true;
  }
  void display(boolean show) {
    if (active) {
      fill((show? color(getColor(value,w*h*0.5),255,255) : #FFFFFF));
      square(x*scl+buffer, y*scl+buffer, scl-buffer*2);
      if (show) {
        fill(0);
        text(value, (x+0.5)*scl, (y+0.45)*scl);
      }
    }
  }
  boolean pressed(int mx, int my) {
    return(active && mx>x*scl+buffer && my>y*scl+buffer&&mx<(x+1)*scl-buffer&&my<(y+1)*scl-buffer);
  }
}
float getColor(int c, float max) {
  return map(c,0,max,0,255);
}
void keyPressed() { //RESET
  if (key == ' ') {
    c = new card[w][h];
    s1 = -1;
    s2 = -1;
    for (int i = 0; i < w; i++) for (int j = 0; j < h; j++) {
      c[i][j] = new card(i, j, floor((i+j*w)/2));
    }
    shuffleBoard(1000);
  }
}

#60 Simple blur
Set the pixel value to the average of all pixels in a*2 by a*2 range. All pixels have the weight of 1.

Change blur by increasing / decreasing ‘a’ variable. Set to 1 to remove blur.

Code
PImage bg;
int a = 32, v = 0;
void settings() {
  bg = loadImage("bg.jpg"); 
  size(bg.width*2, bg.height);
  println(width, height);
}
void draw() {
  loadPixels();
  boolean cont = true;
  for (int i = 0; i < bg.width*5; i++) {
    v+=1;
    int x = v%bg.width, y = floor(v/bg.width);
    if(y>=bg.height-1 && x>=bg.width-2) {noLoop(); cont = false;} 
    if(cont) pixels[x+(y*2+1)*bg.width] = avg(bg, x-a, y-a, a*2, a*2);
  }
  updatePixels();
  if(frameCount<2) image(bg,0,0);
}
color avg(PImage img, int x, int y, float w, float h) {
  int r=0, g=0, b=0;
  float p=0;
  if (x < img.width && y < img.height && x > -w && y > -h) {
    img.loadPixels();
    for (int i = 0; i < w; i++) for (int j = 0; j < h; j++) {
      int xp = x+i, yp = y+j;
      if (xp >= 0 && yp >= 0) {
        p++;
        color pxl = img.pixels[constrain(xp+yp*img.width, 0, bg.width*bg.height-1)];
        r+=red(pxl);
        g+=green(pxl);
        b+=blue(pxl);
      }
    }
  }
  float er = (float)r/p, eg = (float)g/p, eb = (float)b/p;
  return color(er, eg, eb);
}

Original image

#61 THE MANDELBROT SET!!!

It took me a lot of tries to complete. I didn’t want to watch the tutorials, since I wouldn’t understand the process. So after watching tons of youtube videos explaining the mandelbrot set, I had finally done it!

Thank you to Crystalize on discord, for showing me a neat way to create complex numbers in processing.
I made all the basic functions I needed with them and commented out the rest. So right now, there are:
addition, subtraction, multiplication ( C * C or C * R ), division ( C / C or C / R), squaring and z^2+c. If you want to use them, feel free!

Code
complex c = new complex(0, 0);
float scale = 150;
int iter = 1000;
float cx = 300, cy = 300;
color clr[] = new color[iter];
color bg = #FF0000;
void setup() {
  size(600, 600);
  colorMode(HSB);
  noStroke();

  float m = 0.95;
  float v = 1;

  for (int i = 0; i < iter; i++) { //can be replaced with: 255 * pow(m,i) and shorten to a single row
    clr[i] = color((v)*255, 255, 255);
    v*=m;
  }
  clr[iter-1] = #000000; //mandelbrot set is black in the center
}

void draw() {
  loadPixels();
  for (float i = 0; i < width; i ++) for (float j = 0; j < height; j++) {
    if (dist(i, j, width*0.5, height*0.5)<scale*2) {
      complex c = new complex( (i-300.0)/scale, (j-300.0)/scale); //og
      complex d = new complex( (i-300.0)/scale, (j-300.0)/scale); //changes

      int it;
      for (it = 0; it < iter-1 && inBounds(d) == true; it++) {
        complex nw = d.z2pc(d, c);
        d.setValueC( nw );
      }
      pixels[(int)i+(int)j*width] = clr[it];
    } else pixels[(int)i+(int)j*width] = bg;
  }
  updatePixels();
  //if(mousePressed) {
  //  println(((float)mouseX-300.0)/scale, ((float)mouseY-300.0)/scale);
  //}
  noLoop();
}

class complex {
  float re, im;
  complex(float re, float im) {
    this.re = re;
    this.im = im;
  }
  void setValue(float re, float im) {
    this.re = re;
    this.im = im;
  }
  void setValueC(complex c) {
    re = c.re;
    im = c.im;
  }
  complex add(complex z) {
    return new complex(re+z.re, im+z.im);
  }
  //complex sub(complex z) {
  //  return new complex(re-z.re, im-z.im);
  //}
  complex multC(complex z) {
    return new complex(re*z.re - im*z.im, re*z.im + z.re * im);
  }
  //complex multR(float z) {
  //  return new complex(re*z, im*z);
  //}
  complex devC(complex z) {
    return new complex( (re*z.re + im*z.im)/(z.re*z.re+z.im*z.im), (im * z.re - re * z.im)/(z.re*z.re+z.im*z.im) );
  }
  complex squ() {
    return multC(this);
  }
  complex z2pc(complex z, complex c) { //f(z) = z^2 + c
    return z.squ().add(c);
  }
}
void printComplex(complex ccc) {
  println("=" + ccc.re + " + " + ccc.im + "i");
}
boolean inBounds(complex c) {
  return(abs(c.re)<2&&abs(c.im)<2);
}

1 Like

The separate thread about the mandelbrot set I created. It has a few new features and as seen from the title, it has functioning zoom option.