sketch_211116c

FancyBorder.pde

final int N = 2048;

// offset用
float[][] signs = new float[][] {
  {1.0, 1.0}, {-1.0, 1.0}, {-1.0, -1.0}, {1.0, -1.0}
};

int findVertexIndex(float t, int nVertices) {
  for (int k = 0; k < nVertices; k++) {
    float s1 = TWO_PI / nVertices * k;
    float s2 = TWO_PI / nVertices * (k + 1);
    if (s1 <= t && t < s2) {
      return k;
    }
  }
  
  return -1;
}

float[][] randomRadii() {
  float[][] radii = new float[4][2];
  
  radii[0][0] = random(0.2, 0.8);
  radii[0][1] = random(0.2, 0.8);
  radii[1][0] = 1.0 - radii[0][0];
  radii[1][1] = random(0.2, 0.8);
  radii[2][0] = random(0.2, 0.8);
  radii[2][1] = 1.0 - radii[1][1];
  radii[3][0] = 1.0 - radii[2][0];
  radii[3][1] = 1.0 - radii[0][1];
  
  return radii;
}

PGraphics createFancyBorder(float[][] radii) {
  PGraphics pg = createGraphics(800, 800);
  
  pg.beginDraw();
  pg.translate(pg.width / 2.0, pg.height / 2.0);
  pg.rotate(-PI);
  pg.fill(255);
  pg.noStroke();
  pg.beginShape();
  for (int k = 0; k < N; k++) {
    float t = TWO_PI / N * k;
    int i = findVertexIndex(t, 4);
    
    float a = width * radii[i][0];
    float b = height * radii[i][1];
    
    float x = a * cos(t);
    float y = b * sin(t);
    
    float offsetX = signs[i][0] * (width / 2.0 - a);
    float offsetY = signs[i][1] * (height / 2.0 - b);
    
    pg.vertex(x + offsetX, y + offsetY);
  }
  pg.endShape(CLOSE);
  pg.endDraw();
  return pg;
}

Shapes.pde

abstract class AbstractShapeRenderer {
  abstract void drawShape(PGraphics pg, PVector pos, float w, float h, int depth);
}

color getColor() {
  color[] colors = new color[] {
    #08415c,#cc2936,#ebbab9,#388697,#b5ffe1
  };
  return colors[(int)random(colors.length)];
}

class RectShapeRenderer extends AbstractShapeRenderer{
  void drawShape(PGraphics pg, PVector pos, float w, float h, int depth) {
    pg.fill(getColor());
    // stroke(255);
    pg.noStroke();
    
    pg.pushMatrix();
    pg.translate(pos.x, pos.y);
    pg.rect(0, 0, w - 2.5, h - 2.5);
    pg.popMatrix();
    
    pg.strokeWeight(1.0);
  }
}

sketch_211116c.pde

PGraphics pg;
PGraphics mask;
AbstractShapeRenderer[] shapeRendererList;

float[][] radii = new float[][] {
  {0.3, 0.3}, {0.7, 0.3}, {0.7, 0.7}, {0.3, 0.7}
};

void setup() {
  size(800, 800);
  
  mask = createMask();
  
  pg = createGraphics(width, height);
  pg.smooth(8);
  pg.beginDraw();
  pg.background(0);
  pg.rectMode(CENTER);
  pg.endDraw();

  shapeRendererList = new AbstractShapeRenderer[] {
    new RectShapeRenderer()
  };

  noLoop();
}

void draw() {
  background(0);
  drawPattern(pg);
  pg.mask(mask);
  image(pg, 0, 0);
}

void drawPattern(PGraphics pg) {
  float sf = random(1.5, 2.0);
  float[] denominators = new float[] {0.5, 9.0, 8.0, 7.0, 6.0, 5.0};
  float rot = PI / denominators[(int)random(denominators.length)];
  rot = rot * (random(1) > 0.5 ? -1.0 : 1.0);

  int nrows = (int)random(1.0, 4.0);
  int ncols = (int)random(1.0, 4.0);

  // sf = 1.0;
  // rot = 0.0;
  
  pg.beginDraw();
  pg.translate(pg.width / 2.0, pg.height / 2.0);
  pg.scale(sf, sf);
  pg.rotate(rot);

  pg.background(0);
  recur(pg, new PVector(0.0, 0.0), pg.width, pg.height, 0, nrows, ncols);
  pg.endDraw();
}

void recur(PGraphics pg, PVector pos, float w, float h, int depth, int nrows, int ncols) {
  if (depth > 1 && random(1) < float(depth) / 8 || depth == 5) {
    AbstractShapeRenderer shape = shapeRendererList[(int)random(shapeRendererList.length)];
    shape.drawShape(pg, pos, w, h, depth);
  } else {
    float[] hRatios = generateRandomVector(ncols);
    float[] vRatios = generateRandomVector(nrows);
    
    // 横幅と縦幅の累積和を一時的にいれる変数
    float xCum = 0.0;
    float yCum = 0.0;
    
    for (int i = 0; i < nrows; i++) {
      float childHeight = h * vRatios[i];
      
      xCum = 0.0;
      for (int j = 0; j < ncols; j++) {
        // 下層の数の横幅と縦幅
        float childWidth = w * hRatios[j];
        
        // 下層の数が持つノードの数
        int childNRows = (int)random(1.0, 4.0);
        int childNCols = (int)random(1.0, 4.0);
        // 位置
        recur(
          pg,
          new PVector(
            pos.x - w / 2 + xCum + childWidth / 2.0,
            pos.y - h / 2 + yCum + childHeight / 2.0
          ), 
          childWidth, childHeight, 
          depth + 1, childNRows, childNCols
        );
        
        xCum += childWidth;
      }
      
      yCum += childHeight;
    }
  }
}

float[] generateRandomVector(int N) {
  float[] vec = new float[N];
  int s = 0;
  for (int k = 0; k < N; k++) {
    int t = (int)random(4, 10);
    vec[k] = t;
    s += t;
  }
  for (int k = 0; k < N; k++) {
    vec[k] = vec[k] / (float)s;
  }
  return vec;
}

PGraphics createMask() {
  PGraphics mask = createGraphics(width, height);
  PGraphics objImg = createFancyBorder(randomRadii());
  mask.beginDraw();
  mask.background(0);
  mask.translate(mask.width / 2.0, mask.height / 2.0);
  mask.scale((float)mask.width / objImg.width * 0.85);
  mask.imageMode(CENTER);
  mask.shapeMode(CENTER);
  mask.image(objImg, 0, 0);
  mask.filter(THRESHOLD, 0.1);
  mask.filter(BLUR, 3.0);
  mask.endDraw();
  return mask;
}

static final String timestamp(final String name, final String ext) {
  return name + "-" + year() + nf(month(), 2) + nf(day(), 2) +
    "-" + nf(hour(), 2) + nf(minute(), 2) + nf(second(), 2) + ext;
}

void mouseReleased() {
  mask = createMask();
  redraw();
}

void keyReleased() {
  saveFrame(String.format("frames/%s", timestamp("Project", ".png")));
}