231 lines
6.2 KiB
JavaScript
231 lines
6.2 KiB
JavaScript
import p5 from "p5";
|
|
import io from "socket.io-client";
|
|
const socket = io("http://localhost:3000");
|
|
|
|
const params = {
|
|
fps: 60,
|
|
zoom: 1, //in pixels per pixel
|
|
backgroundTicks: 60,
|
|
disableScreen: false,
|
|
textSpread: 0,
|
|
maxSpawns: 1,
|
|
textAlpha: 0.0,
|
|
textTicks: 1,
|
|
};
|
|
|
|
socket.on("paramUpdate", ({ key, value }) => {
|
|
params[key] = value;
|
|
console.log(`Updated param ${key} to ${value}`);
|
|
});
|
|
|
|
let bgTick = 0;
|
|
socket.on("pulse", () => {
|
|
bgTick = 0;
|
|
});
|
|
|
|
const poem =
|
|
"everybody is pretty ugly \
|
|
lover \
|
|
you are my mirror \
|
|
I can't judge this \
|
|
predicament \
|
|
autism alienation and sitting beach \
|
|
this depression's a symptom but it's disease too \
|
|
spaces \
|
|
interiors in city reach peach intention lover drag sleepless depth fear dirt lone";
|
|
const realText = poem.split(" ").filter((t) => t.length > 0);
|
|
|
|
const sketch = (p) => {
|
|
const imageW = 20384,
|
|
imageH = 28064;
|
|
const tileW = 8192;
|
|
const tileH = 8192;
|
|
const tileCols = Math.ceil(imageW / tileW);
|
|
const tileRows = Math.ceil(imageH / tileH);
|
|
const tileCount = tileCols * tileRows;
|
|
const aleph = 0; // to fix tile gaps
|
|
let gl;
|
|
let texArray;
|
|
let shaderProgram;
|
|
|
|
p.setup = async () => {
|
|
p.createCanvas(p.windowWidth, p.windowHeight, p.WEBGL);
|
|
// Check for correct webgl version
|
|
gl = p._renderer.GL;
|
|
if (!(gl instanceof WebGL2RenderingContext)) {
|
|
console.error("WebGL2 required!");
|
|
} else {
|
|
console.log("WebGL2 supported!");
|
|
}
|
|
|
|
// Create texture array
|
|
texArray = gl.createTexture();
|
|
gl.bindTexture(gl.TEXTURE_2D_ARRAY, texArray);
|
|
|
|
// Allocate texture storage
|
|
gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.R8, tileW, tileH, tileCount);
|
|
|
|
const promises = [];
|
|
let n_downloaded = 0;
|
|
|
|
for (let row = 0; row < tileRows; row++) {
|
|
for (let column = 0; column < tileCols; column++) {
|
|
const x = column * tileW;
|
|
const y = row * tileH;
|
|
const w = Math.min(tileW, imageW - x);
|
|
const h = Math.min(tileH, imageH - y);
|
|
promises.push(
|
|
p
|
|
.loadImage(`assets/img/tiles/tile_x${x}_y${y}_w${w}_h${h}.png`)
|
|
.then((img) => {
|
|
img.loadPixels();
|
|
let pixels = new Uint8Array(img.width * img.height);
|
|
for (let i = 0; i < img.pixels.length; i++) {
|
|
pixels[i] = img.pixels[i * 4];
|
|
}
|
|
const i = row * tileCols + column;
|
|
gl.texSubImage3D(
|
|
gl.TEXTURE_2D_ARRAY,
|
|
0,
|
|
0,
|
|
0,
|
|
i,
|
|
img.width,
|
|
img.height,
|
|
1,
|
|
gl.RED,
|
|
gl.UNSIGNED_BYTE,
|
|
pixels,
|
|
);
|
|
n_downloaded++;
|
|
console.log(
|
|
`Downloaded ${n_downloaded} / ${tileCount} (${Math.round((n_downloaded / tileCount) * 100)}%) tiles`,
|
|
);
|
|
}),
|
|
);
|
|
}
|
|
}
|
|
await Promise.all(promises);
|
|
|
|
gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
|
|
shaderProgram = await p.loadShader(
|
|
"shader/shader.vert",
|
|
"shader/shader.frag",
|
|
);
|
|
console.log(shaderProgram);
|
|
|
|
// const shaderFile = await fetch("shader/sobel.frag");
|
|
// const shaderText = await shaderFile.text();
|
|
// sobel = p.createFilterShader(shaderText);
|
|
|
|
// const stream = c.elt.captureStream(60);
|
|
};
|
|
|
|
let textTick = 0;
|
|
let sx, sy;
|
|
let cw, ch;
|
|
let word, bounds;
|
|
|
|
p.draw = () => {
|
|
p.background(220);
|
|
// update scale
|
|
p.setFrameRate(params.fps);
|
|
|
|
bgTick %= params.backgroundTicks;
|
|
|
|
// current width/height
|
|
|
|
if (bgTick++ == 0) {
|
|
cw = Math.floor(p.width * params.zoom);
|
|
ch = Math.floor(p.height * params.zoom);
|
|
// random starting position
|
|
// subtract cw/ch to avoid going out of bounds
|
|
sx = Math.random(0) * (imageW - cw);
|
|
sy = Math.random(0) * (imageH - ch);
|
|
}
|
|
|
|
textTick %= params.textTicks;
|
|
if (textTick++ == 0) {
|
|
(word, (bounds = nextText()));
|
|
}
|
|
drawTiles(sx, sy, cw, ch);
|
|
if (word && bounds) drawText(word, bounds);
|
|
};
|
|
|
|
function nextText() {
|
|
for (let i = 0; i < Math.random() * params.maxSpawns; i++) {
|
|
const word = realText[Math.floor(Math.random() * realText.length)];
|
|
const wx =
|
|
p.windowWidth / 2 -
|
|
p.textWidth(word) / 2 +
|
|
p.random(-params.textSpread, params.textSpread);
|
|
const wy =
|
|
p.windowHeight / 2 -
|
|
p.textAscent() / 2 +
|
|
p.random(-params.textSpread, params.textSpread);
|
|
const bounds = p.textBounds(word, wx, wy);
|
|
return { word, bounds };
|
|
}
|
|
}
|
|
|
|
function drawText(word, bounds) {
|
|
const whitespace = 2;
|
|
p.stroke(0, 0, 0, params.textAlpha);
|
|
p.fill(255, 255, 255, params.textAlpha);
|
|
p.rect(
|
|
bounds.x - whitespace,
|
|
bounds.y - whitespace,
|
|
bounds.w + 2 * whitespace,
|
|
bounds.h + 2 * whitespace,
|
|
);
|
|
|
|
p.noStroke();
|
|
p.fill(0, 0, 0, params.textAlpha);
|
|
p.text(word, bounds.x, bounds.y + p.textAscent());
|
|
}
|
|
|
|
function drawTiles(x, y, width, height) {
|
|
// clear screen
|
|
p.background(p.color(1, 0, 0, 0));
|
|
if (params.disableScreen) return;
|
|
|
|
p.shader(shaderProgram);
|
|
// p.ortho(0, p.width, -p.height, 0);
|
|
p.ortho(x, x + width, -y - height, -y);
|
|
|
|
// Bind texture array
|
|
gl.activeTexture(gl.TEXTURE0);
|
|
gl.bindTexture(gl.TEXTURE_2D_ARRAY, texArray);
|
|
|
|
for (
|
|
let row = Math.floor(y / tileW);
|
|
row <= Math.floor((y + height) / tileW);
|
|
row++
|
|
) {
|
|
for (
|
|
let col = Math.floor(x / tileW);
|
|
col <= Math.floor((x + width) / tileW);
|
|
col++
|
|
) {
|
|
const currentLayer = row * tileCols + col;
|
|
// Tell shader which layer to sample
|
|
shaderProgram.setUniform("uLayer", currentLayer);
|
|
p.noStroke();
|
|
p.rect(
|
|
col * tileW - aleph,
|
|
row * tileH - aleph,
|
|
tileW + 2 * aleph,
|
|
tileH + 2 * aleph,
|
|
);
|
|
// p.rect(0, 0, tileW, tileH);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
new p5(sketch);
|