mirror of
https://gerrit.hackerspace.pl/hscloud
synced 2024-10-18 03:07:44 +00:00
hswaw/site: add badapple
Change-Id: I650ac3bf2a6b499c13c18ad05c26c9e18bbaaa24 Reviewed-on: https://gerrit.hackerspace.pl/c/hscloud/+/1945 Reviewed-by: radex <radex@hackerspace.pl> Reviewed-by: pl <pl@hackerspace.pl>
This commit is contained in:
parent
e8c0952f45
commit
1d1aafb5b0
2 changed files with 92 additions and 0 deletions
|
@ -265,9 +265,101 @@ class Life extends Animation {
|
|||
}
|
||||
}
|
||||
|
||||
// Obligatory bad apple animation.
|
||||
// By q3k.
|
||||
//
|
||||
// Spritesheet was generated from the Youtube video UkgK8eUdpAo.
|
||||
// $ ffmpeg -i input.webm \
|
||||
// -filter:v "format=gray,crop=720:720,scale=16:16" \
|
||||
// badapple-frames/frame%04d.png
|
||||
//
|
||||
// $ cat convert.py
|
||||
// from PIL import Image
|
||||
// import math
|
||||
// nframes = 6572
|
||||
// side = int(math.sqrt(nframes))
|
||||
// if side * side < nframes:
|
||||
// side += 1
|
||||
// print('side', side)
|
||||
// out = [[0 for _ in range(16 * side)] for _ in range(16 * side)]
|
||||
// for i in range(nframes):
|
||||
// ix = i % side
|
||||
// iy = i // side
|
||||
//
|
||||
// img = Image.open(f'frame{i+1:04d}.png')
|
||||
// for y in range(16):
|
||||
// for x in range(16):
|
||||
// v = img.getpixel((x, y))
|
||||
// out[iy*16+y][ix*16+x] = v
|
||||
// img = Image.new(mode='L', size=(side*16, side*16))
|
||||
// for y in range(side*16):
|
||||
// for x in range(side*16):
|
||||
// img.putpixel((x, y), out[y][x])
|
||||
// img.save('badapple.png')
|
||||
class BadApple extends Animation {
|
||||
// loadPixels. Not synchronous because I can't be arsed to make this code
|
||||
// async friendly. That means you might call this, but end up with no
|
||||
// this.pixels yet until stuff is ready.
|
||||
loadPixels() {
|
||||
// Only attempt to load once.
|
||||
if (this.pixelsLoading === undefined) {
|
||||
this.pixelsLoading = true;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do the JS dance to actually get .png pixel data.
|
||||
let img = new window.Image();
|
||||
img.onload = () => {
|
||||
let canvas = document.createElement('canvas');
|
||||
let context = canvas.getContext('2d');
|
||||
let width = img.width;
|
||||
let height = img.height;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
context.drawImage(img, 0, 0, width, height);
|
||||
let imageData = context.getImageData(0, 0, width, height);
|
||||
this.pixels = {
|
||||
data: imageData.data,
|
||||
width: width,
|
||||
height: height,
|
||||
};
|
||||
};
|
||||
img.src = "/static/site/badapple.png";
|
||||
}
|
||||
draw(ts) {
|
||||
if (this.pixels === undefined) {
|
||||
this.loadPixels();
|
||||
return;
|
||||
}
|
||||
// Constants from generation script:
|
||||
const side = 82;
|
||||
const nframes = 6572;
|
||||
const framerate = 30.0;
|
||||
|
||||
const frameno = Math.floor(ts * framerate) % nframes;
|
||||
// Offset of frame within spritesheet.
|
||||
const ix = frameno % side;
|
||||
const iy = Math.floor(frameno / side);
|
||||
for (let x = 0; x < 16; x++) {
|
||||
for (let y = 0; y < 16; y++) {
|
||||
// Pixel position within spritesheet.
|
||||
const xx = ix * 16 + x;
|
||||
const yy = iy * 16 + y;
|
||||
|
||||
// Get pixel data, convert to 0..1, assign.
|
||||
let px = (yy * this.pixels.width + xx) * 4;
|
||||
let v = this.pixels.data[px] / 256.0;
|
||||
this.leds[x][y] = [v, v, v];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add your animations here:
|
||||
export const animations = [
|
||||
Life,
|
||||
SnakeChase,
|
||||
BadApple,
|
||||
];
|
||||
|
||||
|
|
BIN
hswaw/site/static/badapple.png
Normal file
BIN
hswaw/site/static/badapple.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 744 KiB |
Loading…
Reference in a new issue