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

31.94% Statements 23/72
0% Branches 0/17
8.33% Functions 1/12
25.81% Lines 16/62

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 123 124 125 126 127 128        4x       4x       4x       4x                     4x 2134662x 2134662x 2134662x 2134662x     4x 4x                       4x                           4x                                   4x                         4x                                                     4x                
import type { ObjPalette } from "shared/lib/entities/entitiesTypes";
import { ColorCorrectionSetting } 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");
};
 
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[],
  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 || "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;
    }
  }
};