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

31.88% Statements 22/69
0% Branches 0/10
8.33% Functions 1/12
27.59% Lines 16/58

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            5x       5x       5x       5x                     5x 2134926x 2134926x 2134926x 2134926x     5x 5x                       5x                           5x                                   5x           5x                                               5x                
import {
  ColorCorrectionSetting,
  MonoOBJPalette,
} from "shared/lib/resources/types";
 
/* 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 rgb2hex = (r: number, g: number, b: number): string => {
  const hexR = r.toString(16).padStart(2, "0");
  const hexG = g.toString(16).padStart(2, "0");
  const hexB = b.toString(16).padStart(2, "0");
  return `${hexR}${hexG}${hexB}`;
};
 
export const hex2GBCrgb =
  (colorCorrection: ColorCorrectionSetting) => (hex: string) => {
    const gbcHex = hex2GBChex(hex, colorCorrection);
    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,
  colorCorrection: ColorCorrectionSetting,
): string => {
  Iif (colorCorrection === "none") {
    return hex;
  }
  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");
};
 
const indexSpriteColour = (g: number, objPalette: MonoOBJPalette) => {
  Iif (g < 130) return objPalette[2];
  Iif (g < 205) return objPalette[1];
  return objPalette[0];
};
 
export const colorizeSpriteData = (
  mutData: Uint8ClampedArray,
  objPalette: MonoOBJPalette,
  palette: string[],
  colorCorrection: ColorCorrectionSetting,
) => {
  const colorCorrectionFn = hex2GBCrgb(colorCorrection);
  const paletteRGB = palette.map(colorCorrectionFn);
  for (let index = 0; index < mutData.length; index += 4) {
    const colorIndex = indexSpriteColour(mutData[index + 1], objPalette);
    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;
    }
  }
};