All files / src/shared/lib/helpers color.ts

0% Statements 0/62
0% Branches 0/16
0% Functions 0/10
0% Lines 0/53

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                                                                                                                                                                                                                             
import type { ObjPalette } from "shared/lib/entities/entitiesTypes";
 
/* eslint-disable no-param-reassign */
const hexStringToDecimal = (str: string) => {
  return parseInt(str, 16);
};
 
const clamp = (value: number, min: number, max: number) => {
  return Math.min(max, Math.max(min, value));
};
 
const clamp31 = (value: number) => {
  return clamp(value, 0, 31);
};
 
export const hex2rgb = (hex: string) => {
  const r = Math.floor(hexStringToDecimal(hex.substring(0, 2)));
  const g = Math.floor(hexStringToDecimal(hex.substring(2, 4)));
  const b = Math.floor(hexStringToDecimal(hex.substring(4)));
  return {
    r,
    g,
    b,
  };
};
 
export const hex2GBCrgb = (hex: string) => {
  const gbcHex = hex2GBChex(hex);
  const r = Math.floor(hexStringToDecimal(gbcHex.substring(0, 2)));
  const g = Math.floor(hexStringToDecimal(gbcHex.substring(2, 4)));
  const b = Math.floor(hexStringToDecimal(gbcHex.substring(4)));
  return {
    r,
    g,
    b,
  };
};
 
export const hex2GBChex = (hex: string): string => {
  const r = clamp31(Math.floor(hexStringToDecimal(hex.substring(0, 2)) / 8));
  const g = clamp31(Math.floor(hexStringToDecimal(hex.substring(2, 4)) / 8));
  const b = clamp31(Math.floor(hexStringToDecimal(hex.substring(4)) / 8));
  return rgb5BitToGBCHex(r, g, b).toUpperCase();
};
 
/* 5-bit rgb value => GBC representative hex value */
export const rgb5BitToGBCHex = (
  red5: number,
  green5: number,
  blue5: number
) => {
  const value = (blue5 << 10) + (green5 << 5) + red5;
  const r = value & 0x1f;
  const g = (value >> 5) & 0x1f;
  const b = (value >> 10) & 0x1f;
  return (
    (((r * 13 + g * 2 + b) >> 1) << 16) |
    ((g * 3 + b) << 9) |
    ((r * 3 + g * 2 + b * 11) >> 1)
  )
    .toString(16)
    .padStart(6, "0");
};
 
export const indexSpriteColour = (g: number, objPalette: ObjPalette) => {
  Iif (g < 65) {
    return 3;
  }
  Iif (g < 130) {
    return objPalette === "OBP1" ? 2 : 3;
  }
  Iif (g < 205) {
    return objPalette === "OBP1" ? 2 : 1;
  }
  return 0;
};
 
export const colorizeSpriteData = (
  mutData: Uint8ClampedArray,
  objPalette: ObjPalette | null,
  palette: string[]
) => {
  const paletteRGB = palette.map(hex2GBCrgb);
  for (let index = 0; index < mutData.length; index += 4) {
    const colorIndex = indexSpriteColour(
      mutData[index + 1],
      objPalette || "OBP0"
    );
    const color = paletteRGB[colorIndex];
    const r = mutData[index];
    const g = mutData[index + 1];
    const b = mutData[index + 2];
    Iif ((g > 249 && r < 180 && b < 20) || (b >= 200 && g < 20)) {
      // Set transparent background on pure green & magenta
      mutData[index + 3] = 0;
    }
    mutData[index] = color.r;
    mutData[index + 1] = color.g;
    mutData[index + 2] = color.b;
  }
};
 
export const chromaKeyData = (mutData: Uint8ClampedArray) => {
  for (let index = 0; index < mutData.length; index += 4) {
    Iif (mutData[index + 1] === 255) {
      // Set transparent background on pure green
      mutData[index + 3] = 0;
    }
  }
};