Can you get the words in punched multilayers?
It's an art you need to see the source code to understand.
It's a creative coding artwork written in Processing. It creates a multilayer with punch holes.
Recently, I've written some code that uses multilayer.
This time I concentrated my attention on 'punch hole'. I punched on the layer with 'blendMode(REPLACE)' And I applied 'Shining Mountain' code to draw patterns on the layer.
'blendMode(REPLACE)' is easy to use and I can write a code intuitively.
I prepared several drawing patterns and punch styles and I used them randomly.
And I put a word in it. You may not read that word on the image. You should see the source code to see the word. This is my 'Art'. The appreciation of this art not complete without reading the source code.
I used to think 'My work is not the output image, but the source code', so this work is an interesting trial to me.
The 'Processing' example code.
Please feel free to use this example code under the terms of the GPL. To see other works based on my code is my pleasure. And my honor.
This code does not display any images on the screen but generates image files in frames directory.
/**
* Crime of the Century.
* Can you get the word in punched multilayers?
*
* @author @deconbatch
* @version 0.1
* @license GPL Version 3 http://www.gnu.org/licenses/
* Processing 3.5.3
* 2021.05.16
*/
void setup() {
size(640, 1040);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
smooth();
}
void draw() {
int layerMax = 5;
float hueBase = random(360.0);
Wall wl;
Puncher pc;
// bottom layer
blendMode(BLEND);
wl = getRandomWall(hueBase);
image(wl.drawPattern(90.0), 0.0, 0.0);
// middle layers
blendMode(BLEND);
for (int layerCnt = 0; layerCnt < layerMax; layerCnt++) {
float layerRatio = map(layerCnt, 0, layerMax, 0.0, 1.0);
wl = getRandomWall(hueBase + 30.0 + 150.0 * layerRatio);
pc = getRandomPuncher();
image(pc.punch(wl.drawPattern(90.0 - 50.0 * layerRatio)), 0.0, 0.0);
}
// reverse punch layer
blendMode(BLEND);
pc = new WordPuncher();
PImage img = pc.punch(get());
wl = getRandomWall(hueBase + 60.0);
image(wl.drawPattern(10.0), 0.0, 0.0);
image(img, 0.0, 0.0);
// top layer
blendMode(BLEND);
wl = getRandomWall(hueBase + 60.0);
pc = new PackCirclePuncher();
image(pc.punch(wl.drawPattern(30.0)), 0.0, 0.0);
casing();
saveFrame("frames/####.png");
exit();
}
/**
* getRandomWall : returns random class
*/
Wall getRandomWall(float _hue) {
float sel = random(1.0);
if (sel < 0.3) {
return new CircleCenter(_hue);
} else if (sel < 0.6) {
return new RectCenter(_hue);
} else {
return new RectCorner(_hue);
}
}
/**
* getRandomPuncher : returns random class
*/
Puncher getRandomPuncher() {
float sel = random(1.0);
if (sel < 0.25) {
return new PackCirclePuncher();
} else if (sel < 0.5) {
return new PackRectPuncher();
} else if (sel < 0.75) {
return new MatrixPackCirclePuncher();
} else {
return new MatrixPackRectPuncher();
}
}
/**
* casing : draws fancy casing
*/
void casing() {
float w = min(width, height) * 0.05;
fill(0.0, 0.0, 0.0, 0.0);
strokeWeight(w + 4.0);
stroke(0.0, 0.0, 0.0, 100.0);
rect(0.0, 0.0, width, height);
strokeWeight(w);
stroke(0.0, 0.0, 100.0, 100.0);
rect(0.0, 0.0, width, height);
}
/**
* Wall : draws various patterns
*/
abstract class Wall {
int stepDiv;
float briMin;
float briMax;
float hueBase;
Wall(float _hue) {
// set pattern base parameters
hueBase = _hue;
if (random(1.0) < 0.5) {
stepDiv = 12;
briMin = 5.0;
briMax = 11.0;
} else {
stepDiv = 20;
briMin = 2.0;
briMax = 8.0;
}
}
/**
* drawCell : draws pattern cell
*/
abstract void drawCell(PGraphics _p, float _size);
/**
* setBlendMode : change blend mode randomly
*/
void setBlendMode(PGraphics _p) {
if (random(1.0) < 0.4) {
_p.blendMode(DIFFERENCE);
} else {
_p.blendMode(SCREEN);
}
}
/**
* drawPattern : draws pattern
*/
PImage drawPattern(float _briBack) {
int stepMax = stepDiv * 4;
noiseSeed(floor(random(100.0)));
PGraphics p = createGraphics(width, height);
p.beginDraw();
p.colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
p.background((hueBase + 90.0) % 360.0, 40.0, _briBack, 100.0);
p.noStroke();
for (int step = stepDiv; step < stepMax; step += stepDiv) {
for (int cellSiz = 1; cellSiz < step; cellSiz++) {
for (int x = 0; x <= width; x += step) {
for (int y = 0; y <= height; y += step) {
p.fill(
(hueBase + random(120.0)) % 360,
noise(10.0, x * 0.05, y * 0.05) * 50.0,
noise(90.0, x * 0.05, y * 0.05) * map(step, stepDiv, stepMax, briMax, briMin),
100.0
);
p.pushMatrix();
p.translate(x, y);
setBlendMode(p);
drawCell(p, cellSiz);
p.popMatrix();
}
}
}
}
p.endDraw();
return p;
}
}
/**
* Wall classes
*/
class CircleCenter extends Wall {
CircleCenter(float _hue) {
super(_hue);
}
void drawCell(PGraphics _p, float _size) {
_p.ellipse(0, 0, _size, _size);
}
}
class RectCenter extends Wall {
RectCenter(float _hue) {
super(_hue);
}
void drawCell(PGraphics _p, float _size) {
_p.rectMode(CENTER);
_p.rect(0, 0, _size, _size);
}
}
class RectCorner extends Wall {
RectCorner(float _hue) {
super(_hue);
}
void drawCell(PGraphics _p, float _size) {
_p.rect(0, 0, _size, _size);
}
}
/**
* Puncher : returns punched image
*/
interface Puncher {
PImage punch(PImage _img);
}
/**
* Puncher classes
*/
class MatrixPackRectPuncher implements Puncher {
PImage punch(PImage _img) {
PGraphics pg = createGraphics(width, height);
pg.beginDraw();
pg.colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
pg.rectMode(CENTER);
pg.background(0.0, 0.0, 0.0, 0.0);
pg.image(_img, 0.0, 0.0);
pg.blendMode(REPLACE);
pg.noStroke();
float div = min(width, height) / floor(random(3.0, 8.0));
for (float x = div * 0.5; x < width; x += div) {
for (float y = div * 0.5; y < height; y += div) {
if (random(1.0) < 0.6) {
float eBri = (random(1.0) < 0.8) ? 0.0 : 80.0;
for (int i = 0; i < 50; i++) {
float alp = constrain(map(i, 0, 50, 70.0, -15.0), 0.0, 100.0);
float eR = div * map(i, 0, 50, 1.0, 0.0);
pg.fill(0.0, 0.0, eBri, alp);
punchShape(pg, x, y, eR);
}
}
}
}
pg.endDraw();
return pg;
}
void punchShape(PGraphics _p, float _x, float _y, float _s) {
_p.rect(_x, _y, _s, _s);
}
}
class MatrixPackCirclePuncher extends MatrixPackRectPuncher {
void punchShape(PGraphics _p, float _x, float _y, float _s) {
_p.ellipse(_x, _y, _s, _s);
}
}
class PackRectPuncher implements Puncher {
ArrayList<PunchHole> pcs;
class PunchHole {
public float x, y, r;
PunchHole(float _x, float _y, float _r) {
x = _x;
y = _y;
r = _r;
}
}
// circle packing
PackRectPuncher() {
pcs = new ArrayList<PunchHole>();
int punchNo = 200;
int tryMax = 10000; // a trying count to add and grow circle.
float gap = 10.0;
float allow = 1; // allow how many collision
pcs.add(new PunchHole(width * 0.5, height * 0.5, min(width, height) * 0.5));
for (int tryCnt = 0; tryCnt < tryMax; tryCnt++) {
float newX = random(width);
float newY = random(height);
Boolean addPuncher = false;
if (tryCnt % 10 == 0) {
addPuncher = true;
}
for (PunchHole pThis : pcs) {
int collision = 0;
// canvas edge
float hr = pThis.r * 0.5;
if (pThis.x + hr >= width) {
pThis.x -= gap * 0.5;
}
if (pThis.x - hr <= 0.0) {
pThis.x += gap * 0.5;
}
if (pThis.y + hr >= height) {
pThis.y -= gap * 0.5;
}
if (pThis.y - hr <= 0.0) {
pThis.y += gap * 0.5;
}
// collision
for (PunchHole pThat : pcs) {
if (pThis != pThat) {
if (dist(pThis.x, pThis.y, pThat.x, pThat.y) < (pThis.r + pThat.r) * 0.5 + gap) {
collision++;
}
}
}
if (collision < allow) {
pThis.r += gap * 0.5;
}
// add new puncher
if (
pcs.size() > punchNo ||
dist(pThis.x, pThis.y, newX, newY) < pThis.r * 0.5 + gap
) {
addPuncher = false;
}
}
if (addPuncher) {
pcs.add(new PunchHole(newX, newY, 0.0));
}
}
}
PImage punch(PImage _img) {
PGraphics pg = createGraphics(width, height);
pg.beginDraw();
pg.colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
pg.rectMode(CENTER);
pg.background(0.0, 0.0, 0.0, 0.0);
pg.image(_img, 0.0, 0.0);
pg.blendMode(REPLACE);
pg.noStroke();
for (PunchHole pc : pcs) {
float eBri = (random(1.0) < 0.8) ? 0.0 : 80.0;
for (int i = 0; i < 50; i++) {
float alp = constrain(map(i, 0, 50, 70.0, -15.0), 0.0, 100.0);
float eR = pc.r * map(i, 0, 50, 1.0, 0.0);
pg.fill(0.0, 0.0, eBri, alp);
punchShape(pg, pc.x, pc.y, eR);
}
}
pg.endDraw();
return pg;
}
void punchShape(PGraphics _p, float _x, float _y, float _s) {
_p.rect(_x, _y, _s, _s);
}
}
class PackCirclePuncher extends PackRectPuncher {
ArrayList<PunchHole> pcs;
PackCirclePuncher() {
super();
}
void punchShape(PGraphics _p, float _x, float _y, float _s) {
_p.ellipse(_x, _y, _s, _s);
}
}
class WordPuncher implements Puncher {
String crimes[] = {
"Suppression",
"Instigation",
"Concealment",
"Falsification",
"Discrimination",
"Invasion",
"Oppression",
};
PImage punch(PImage _img) {
PGraphics pg = createGraphics(width, height);
pg.beginDraw();
pg.colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
pg.background(0.0, 0.0, 0.0, 0.0);
pg.image(_img, 0.0, 0.0);
pg.blendMode(REPLACE);
pg.noStroke();
pg.fill(0.0, 0.0, 0.0, 0.0);
pg.textSize(60.0);
pg.textAlign(CENTER, CENTER);
int crimeNum = 5;
float yDiv = height / crimeNum;
for (int i = 0; i < crimeNum; i++) {
pg.text(
crimes[floor(random(crimes.length))],
random(width),
(0.5 + i) * yDiv
);
}
pg.endDraw();
return pg;
}
}
/*
Copyright (C) 2021- deconbatch
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/