Skip to content

Commit

Permalink
feat: HSV lerp for rgb colors
Browse files Browse the repository at this point in the history
  • Loading branch information
PeenScreeker committed Dec 2, 2023
1 parent 2955ded commit 16bcaa1
Showing 1 changed file with 70 additions and 2 deletions.
72 changes: 70 additions & 2 deletions scripts/util/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,78 @@ function rgbaTupleLerp(colorA: RgbaTuple, colorB: RgbaTuple, alpha: number): Rgb
* Blends two colors linearly (not HSV lerp).
* RGB inputs are converted to RGBA with A value of 1.
*/
function rgbaStringLerp(colorA: string, colorB: string, alpha: number): string {
function rgbaStringLerp(colorA: string, colorB: string, alpha: number, useHsv: boolean = false): string {
const arrayA = rgbaStringToTuple(colorA);
const arrayB = rgbaStringToTuple(colorB);
return tupleToRgbaString(rgbaTupleLerp(arrayA, arrayB, alpha));
if (!useHsv) return tupleToRgbaString(rgbaTupleLerp(arrayA, arrayB, alpha));

const FromHSV: RgbaTuple = LinearRGBToHSV(arrayA) as RgbaTuple;
const ToHSV: RgbaTuple = LinearRGBToHSV(arrayB) as RgbaTuple;

// Take the shortest path to the new hue
if (Math.abs(FromHSV[0] - ToHSV[0]) > 180) {
if (ToHSV[0] > FromHSV[0]) {
FromHSV[0] += 360;
} else {
ToHSV[0] += 360;
}
}
const newHsv = rgbaTupleLerp(FromHSV, ToHSV, alpha);

newHsv[0] = newHsv[0] % 360;
if (newHsv[0] < 0) {
newHsv[0] += 360;
}

const newRgb: RgbaTuple = HSVToLinearRGB(newHsv) as RgbaTuple;

return tupleToRgbaString(newRgb);
}
/** Converts an HSV color to a linear space RGB color */
function HSVToLinearRGB([h, s, v, a]: RgbaTuple): number[] {
const hueDir = h / 60;
const hueDir_Floor = Math.floor(hueDir);

Check warning on line 92 in scripts/util/colors.ts

View workflow job for this annotation

GitHub Actions / build

Identifier 'hueDir_Floor' is not in camel case
const hueDir_Fraction = hueDir - hueDir_Floor;

Check warning on line 93 in scripts/util/colors.ts

View workflow job for this annotation

GitHub Actions / build

Identifier 'hueDir_Fraction' is not in camel case

Check warning on line 93 in scripts/util/colors.ts

View workflow job for this annotation

GitHub Actions / build

Identifier 'hueDir_Floor' is not in camel case

const RGBValues: RgbaTuple = [v, v * (1 - s), v * (1 - hueDir_Fraction * s), v * (1 - (1 - hueDir_Fraction) * s)];

Check warning on line 95 in scripts/util/colors.ts

View workflow job for this annotation

GitHub Actions / build

Identifier 'hueDir_Fraction' is not in camel case

Check warning on line 95 in scripts/util/colors.ts

View workflow job for this annotation

GitHub Actions / build

Identifier 'hueDir_Fraction' is not in camel case
const RGBSwizzle = [
[0, 3, 1],
[2, 0, 1],
[1, 0, 3],
[1, 2, 0],
[3, 1, 0],
[0, 1, 2]
];
const SwizzleIndex = hueDir_Floor % 6;

Check warning on line 104 in scripts/util/colors.ts

View workflow job for this annotation

GitHub Actions / build

Identifier 'hueDir_Floor' is not in camel case

return [
RGBValues[RGBSwizzle[SwizzleIndex][0]] * 255,
RGBValues[RGBSwizzle[SwizzleIndex][1]] * 255,
RGBValues[RGBSwizzle[SwizzleIndex][2]] * 255,
a
];
}

function LinearRGBToHSV([r, g, b, a]: RgbaTuple): number[] {
const RGBMin = Math.min(r, g, b);
const RGBMax = Math.max(r, g, b);
const RGBRange = RGBMax - RGBMin;

const Hue =
RGBMax === RGBMin
? 0
: RGBMax === r
? (((g - b) / RGBRange) * 60 + 360) % 360
: RGBMax === g
? ((b - r) / RGBRange) * 60 + 120
: RGBMax === b
? ((r - g) / RGBRange) * 60 + 240
: 0;

const Saturation = RGBMax === 0 ? 0 : RGBRange / RGBMax;
const Value = RGBMax / 255;

return [Hue, Saturation, Value, a];
}

/**
Expand Down

0 comments on commit 16bcaa1

Please sign in to comment.