Files
noise-fields/frontend/js/sketch.js
T

220 lines
5.9 KiB
JavaScript

import p5 from "p5";
import io from "socket.io-client";
import UPNG from "upng-js";
const socket = io("http://localhost:3000");
const params = {
fps: 60,
zoom: 0.1,
backgroundTicks: 60,
textSpread: 0,
maxSpawns: 1,
textAlpha: 0.0,
textTicks: 1,
};
socket.on("paramUpdate", ({ key, value }) => {
params[key] = value;
console.log(`Updated param ${key} to ${value}`);
});
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;
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(
fetch(`assets/img/tiles/tile_x${x}_y${y}_w${w}_h${h}.png`)
.then((res) => res.arrayBuffer())
.then((buffer) => {
const img = UPNG.decode(buffer);
console.log(
`img.data.length: ${img.data.length}, img.width: ${img.width}, img.height: ${img.height}`,
);
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,
img.data,
);
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 bgTick = 0;
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(imageW * params.zoom);
ch = Math.floor(imageH * 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(0);
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.rect(col * tileW, row * tileH, tileW, tileH);
// p.rect(0, 0, tileW, tileH);
}
}
}
};
new p5(sketch);