All files / src/components/world TilePreview.worker.ts

0% Statements 0/60
0% Branches 0/12
0% Functions 0/4
0% Lines 0/57

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122                                                                                                                                                                                                                                                   
import { TILE_SIZE } from "consts";
import { hex2GBCrgb } from "shared/lib/helpers/color";
 
// eslint-disable-next-line no-restricted-globals
const workerCtx: Worker = self as unknown as Worker;
 
const indexColour = (g: number) => {
  Iif (g < 65) {
    return 3;
  }
  Iif (g < 130) {
    return 2;
  }
  Iif (g < 205) {
    return 1;
  }
  return 0;
};
 
interface CacheRecord {
  canvas: OffscreenCanvas;
  ctx: OffscreenCanvasRenderingContext2D;
  img: ImageBitmap;
}
 
export interface TilePreviewResult {
  id: number;
  canvasImage: ImageBitmap;
}
 
const cache: Record<string, CacheRecord> = {};
 
workerCtx.onmessage = async (evt) => {
  const id = evt.data.id;
  const src = evt.data.src;
  const tileIndex = evt.data.tileIndex ?? 0;
  const tileSize = evt.data.tileSize === "16px" ? TILE_SIZE * 2 : TILE_SIZE;
  const palette = evt.data.palette;
  const paletteRGB = palette.map(hex2GBCrgb);
 
  let canvas: OffscreenCanvas;
  let ctx: OffscreenCanvasRenderingContext2D;
  let img: ImageBitmap;
 
  if (cache[src]) {
    // Using Cached Data
    canvas = cache[src].canvas;
    ctx = cache[src].ctx;
    img = cache[src].img;
  } else {
    // Fetch New Data
    const imgblob = await fetch(src).then((r) => r.blob());
    img = await createImageBitmap(imgblob);
 
    canvas = new OffscreenCanvas(tileSize, tileSize);
 
    const tmpCtx = canvas.getContext("2d");
    Iif (!tmpCtx) {
      return;
    }
    ctx = tmpCtx;
 
    cache[src] = {
      canvas,
      ctx,
      img,
    };
  }
 
  const tileWidth = Math.floor(img.width / TILE_SIZE);
 
  const offsetX = TILE_SIZE * (tileIndex % tileWidth);
  const offsetY = TILE_SIZE * Math.floor(tileIndex / tileWidth);
 
  canvas.width = tileSize;
  canvas.height = tileSize;
 
  ctx.drawImage(
    img,
    offsetX,
    offsetY,
    tileSize,
    tileSize,
    0,
    0,
    tileSize,
    tileSize
  );
 
  const imageData = ctx.getImageData(0, 0, tileSize, tileSize);
  const data = imageData.data;
 
  const p1X = 0;
  const p2X = tileSize;
  const p1Y = 0;
  const p2Y = tileSize;
  for (let pX = p1X; pX < p2X; pX++) {
    for (let pY = p1Y; pY < p2Y; pY++) {
      const index = (pX + pY * tileSize) * 4;
      const colorIndex = indexColour(data[index + 1]);
      const color = paletteRGB[colorIndex];
      data[index] = color.r;
      data[index + 1] = color.g;
      data[index + 2] = color.b;
      data[index + 3] = 255;
    }
  }
 
  ctx.putImageData(imageData, 0, 0);
 
  const canvasImage = canvas.transferToImageBitmap();
  workerCtx.postMessage({ id, canvasImage }, [canvasImage]);
};
 
// -----------------------------------------------------------------
 
export default class W extends Worker {
  constructor() {
    super("");
  }
}