diff --git a/frontend/js/sketch.js b/frontend/js/sketch.js index 15878a0..4b6027a 100644 --- a/frontend/js/sketch.js +++ b/frontend/js/sketch.js @@ -18,7 +18,6 @@ socket.on("paramUpdate", ({ key, value }) => { console.log(`Updated param ${key} to ${value}`); }); -let bg; let cw = 1; let ch = 1; @@ -31,23 +30,44 @@ predicament \ autism alienation and sitting beach \ this depression's a symptom but it's disease too \ spaces \ -interiors in berlin city reach peach intention lover drag sleepless depth fear dirt lone"; +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) => { let sobel; - const imageW = 37418, - imageH = 27178; + const imageW = 20384, + imageH = 28064; const tileW = 8192; - const tileH = 4096; + const tileH = 8192; const tileCols = Math.ceil(imageW / tileW); const tileRows = Math.ceil(imageH / tileH); const tileCount = tileCols * tileRows; const tiles = []; + const tileTextures = []; + let gl; + let texArray; + let shaderProgram; + p.setup = async () => { - // bg = await p.loadImage("assets/scans/1200dpi 16bit grayscale.png"); + 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; @@ -55,29 +75,28 @@ const sketch = (p) => { const w = Math.min(tileW, imageW - x); const h = Math.min(tileH, imageH - y); promises.push( - fetch( - `assets/img/tiles/37418x27178_3200dpi_16bit_grayscale/tile_x${x}_y${y}_w${w}_h${h}.png`, - ) + fetch(`assets/img/tiles/tile_x${x}_y${y}_w${w}_h${h}.png`) .then((res) => res.arrayBuffer()) .then((buffer) => { - // divide width by 2 because we are colorpacking - const p5img = p.createImage(w / 2, h); - p5img.loadPixels(); - - console.log( - `p5img.pixels.length: ${p5img.pixels.length}, p5img.width: ${p5img.width}, p5img.height: ${p5img.height}`, - ); - const img = UPNG.decode(buffer); console.log( `img.data.length: ${img.data.length}, img.width: ${img.width}, img.height: ${img.height}`, ); - // BEWARE: weird things happening with dimension of the loaded image (4096 values too many) - for (let i = 0; i < w * h * 4; i++) { - p5img.pixels[i] = img.data[i]; - } - tiles[row * tileCols + column] = img; + 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`, @@ -87,14 +106,18 @@ const sketch = (p) => { } } await Promise.all(promises); - p.createCanvas(p.windowWidth, p.windowHeight, p.WEBGL); - const shaderFile = await fetch("shader/sobel.frag"); - const shaderText = await shaderFile.text(); - sobel = p.createFilterShader(shaderText); - console.log( - "Max texture size:", - p._renderer.GL.getParameter(p._renderer.GL.MAX_TEXTURE_SIZE), - ); + + 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 = p.loadShader("shader/shader.vert", "shader/shader.frag"); + + // const shaderFile = await fetch("shader/sobel.frag"); + // const shaderText = await shaderFile.text(); + // sobel = p.createFilterShader(shaderText); + // const stream = c.elt.captureStream(60); }; @@ -160,7 +183,22 @@ const sketch = (p) => { p.text(word, bounds.x, bounds.y + p.textAscent()); } - function drawTiles(x, y, width, height) {} + function drawTiles(x, y, width, height) { + p.ortho(x, x + width, y, y + height); + 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++ + ) { + p.image(tiles[row * tileCols + col], col * tileW, row * tileH); + } + } + } }; new p5(sketch); diff --git a/frontend/shader/shader.frag b/frontend/shader/shader.frag new file mode 100644 index 0000000..a2cab19 --- /dev/null +++ b/frontend/shader/shader.frag @@ -0,0 +1,13 @@ +#version 300 es +precision highp float; + +in vec2 vTexCoord; +out vec4 fragColor; + +uniform sampler2DArray uTexArray; +uniform int uLayer; + +void main() { + float value = texture(uTexArray, vec3(vTexCoord, float(uLayer))).r; + fragColor = vec4(vec3(value), 1.0); +} diff --git a/frontend/shader/shader.vert b/frontend/shader/shader.vert new file mode 100644 index 0000000..7fb612f --- /dev/null +++ b/frontend/shader/shader.vert @@ -0,0 +1,12 @@ +#version 300 es +precision highp float; + +in vec3 aPosition; +in vec2 aTexCoord; + +out vec2 vTexCoord; + +void main() { + vTexCoord = aTexCoord; + gl_Position = vec4(aPosition, 1.0); +} diff --git a/frontend/scripts/tile.sh b/scripts/tile.sh similarity index 76% rename from frontend/scripts/tile.sh rename to scripts/tile.sh index 3a77d2d..dbfd4f7 100755 --- a/frontend/scripts/tile.sh +++ b/scripts/tile.sh @@ -1,4 +1,5 @@ #!/bin/bash +# magick input.png -colorspace Gray -auto-level -dither FloydSteinberg -depth 8 output.png INPUT="$1" OUTPUT_DIR="tiles" @@ -13,7 +14,7 @@ echo "Image dimensions: $WIDTH x $HEIGHT" #Tile dimensions TILE_WIDTH=8192 -TILE_HEIGHT=4096 +TILE_HEIGHT=8192 echo "Cutting image into tiles of ${TILE_WIDTH}x${TILE_HEIGHT}..." @@ -28,7 +29,8 @@ for (( y=0; y_y_w_h.png TILE_FILE="$OUTPUT_DIR/tile_x${x}_y${y}_w${W}_h${H}.png" echo "Creating $TILE_FILE" - convert "$INPUT" -crop "${TILE_WIDTH}x${TILE_HEIGHT}+${x}+${y}" +repage "$TILE_FILE" + # convert "$INPUT" -crop "${TILE_WIDTH}x${TILE_HEIGHT}+${x}+${y}" +repage "$TILE_FILE" + vips extract_area "$INPUT" "$TILE_FILE" "$x" "$y" "$W" "$H" ((count++)) done done