(async () => { | |
const cols = 44 | |
const rows = 36 | |
const size = 90 | |
const speedX = 0.02 | |
const speedY = 0.0 | |
const loadImage = url => { | |
const img = document.createElement('img') | |
img.crossOrigin = true | |
return new Promise(resolve => { | |
img.onload = () => resolve(img) | |
img.src = url | |
}) | |
} | |
document.body.innerHTML = '' | |
document.body.style = 'margin: 0; background: palegoldenrod; display: flex; flex-direction: column; justify-content: center; align-items: center;' | |
// const img = await loadImage('https://i.imgur.com/umlMniN.png') | |
// const img = await loadImage('https://i.imgur.com/AVjtBoG.png') | |
const img = await loadImage('https://i.imgur.com/VhXMCPu.png') | |
const imgHeight = Math.round(size / img.width * img.height) | |
window.img = img | |
const canvas = document.createElement('canvas') | |
window.canvas = canvas | |
canvas.width = size * Math.ceil(cols / size) | |
canvas.height = imgHeight * Math.ceil(rows / imgHeight) | |
const ctx = canvas.getContext('2d') | |
window.ctx = ctx | |
document.body.appendChild(canvas) | |
const textarea = document.createElement('textarea') | |
textarea.addEventListener('click', textarea.select) | |
document.body.appendChild(textarea) | |
const output = document.createElement('canvas') | |
output.width = cols | |
output.height = rows | |
output.style = 'background: white; width: 440px; height: 360px; image-rendering: pixelated' | |
const ctx2 = output.getContext('2d') | |
document.body.appendChild(output) | |
ctx.fillStyle = 'black' | |
ctx.fillRect(0,0, canvas.width, canvas.height) | |
// ctx.imageSmoothingEnabled = false | |
const tile = (img, size, offset = 0) => { | |
let x = offset | |
while (x <= canvas.width) { | |
let y = offset | |
while (y <= canvas.height) { | |
ctx.drawImage(img, x, y, size, imgHeight) | |
y += imgHeight | |
} | |
x += size | |
} | |
} | |
tile(img, size) | |
const { data, width, height } = ctx.getImageData(0, 0, canvas.width, canvas.height) | |
const json = JSON.stringify({ | |
width, height, data: [...data], | |
speedX, speedY | |
}) | |
textarea.value = `const texture = ${json}` | |
// REPLACE THIS WITH THE JSON | |
const texture = JSON.parse(json) | |
// RENDER TO THE ARCH | |
function paintTexture(frame, rows, cols, frameX, frameY) { | |
const x_frac = frameX - Math.floor(frameX) | |
const y_frac = frameY - Math.floor(frameY) | |
const lerp = (line, j, x_a, x_b, y_a, y_b) => { | |
for (let i = 0; i < 3; i++) { | |
line[j * 3 + i] = ( | |
x_frac * y_frac * texture.data[y_b + x_b + i] + | |
(1 - x_frac) * y_frac * texture.data[y_b + x_a + i] + | |
x_frac * (1 - y_frac) * texture.data[y_a + x_b + i] + | |
(1 - x_frac) * (1 - y_frac) * texture.data[y_a + x_a + i] | |
) | |
} | |
} | |
for (let i = 0; i < rows; i++) { | |
const texRowA = texture.width * 4 * (Math.floor(i + frameY) % texture.height) | |
const texRowB = texture.width * 4 * (Math.ceil (i + frameY) % texture.height) | |
const lineSize = cols * 3; | |
const line = frame.subarray(lineSize * i, lineSize* (i + 1)); | |
for (let j = 0; j < cols; j++) { | |
const texColA = 4 * (Math.floor(j + frameX) % texture.width) | |
const texColB = 4 * (Math.ceil (j + frameX) % texture.width) | |
lerp(line, j, texColA, texColB, texRowA, texRowB) | |
} | |
} | |
} | |
/*export*/ function transform(buffer, rows, cols, frameCount, fps, isFirst) { | |
const frameSize = 3 * rows * cols; | |
for (let i = 0; i < frameCount; i++) { | |
const second = i / fps; | |
const frame = new Uint8Array(buffer, frameSize * i, frameSize); | |
paintTexture(frame, rows, cols, 10000 + i * texture.speedX, 10000 + i * texture.speedY) | |
} | |
} | |
/* | |
export default function () { | |
return Promise.resolve({ | |
transform, | |
}) | |
} | |
*/ | |
// END RENDER CODE | |
const frameCount = 35 * 2 | |
const frameSize = 3 * 36 * 44 | |
const fps = 35 | |
const buffer = new ArrayBuffer(rows * cols * 3 * frameCount) | |
transform(buffer, rows, cols, frameCount, fps, false) | |
window.buffer = buffer | |
if (window.lastTimeout) clearTimeout(window.lastTimeout) | |
let frameNr = 0 | |
const draw = () => { | |
window.lastTimeout = setTimeout(draw, Math.round(1000 / fps)) | |
const frame = new ImageData(44, 36) | |
const image = new Uint8Array(buffer, frameNr * frameSize, frameSize) | |
for (let i = 0; i < frameSize; i++) { | |
frame.data[i * 4 + 0] = image[i * 3 + 0] | |
frame.data[i * 4 + 1] = image[i * 3 + 1] | |
frame.data[i * 4 + 2] = image[i * 3 + 2] | |
frame.data[i * 4 + 3] = 255 | |
} | |
ctx2.putImageData(frame, 0, 0) | |
frameNr = (frameNr + 1) % frameCount | |
} | |
draw() | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment