rot-js
Version:
A roguelike toolkit in JavaScript
337 lines (336 loc) • 10 kB
JavaScript
import { clamp } from "./util.js";
import RNG from "./rng.js";
export function fromString(str) {
let cached, r;
if (str in CACHE) {
cached = CACHE[str];
}
else {
if (str.charAt(0) == "#") { // hex rgb
let matched = str.match(/[0-9a-f]/gi) || [];
let values = matched.map((x) => parseInt(x, 16));
if (values.length == 3) {
cached = values.map((x) => x * 17);
}
else {
for (let i = 0; i < 3; i++) {
values[i + 1] += 16 * values[i];
values.splice(i, 1);
}
cached = values;
}
}
else if ((r = str.match(/rgb\(([0-9, ]+)\)/i))) { // decimal rgb
cached = r[1].split(/\s*,\s*/).map((x) => parseInt(x));
}
else { // html name
cached = [0, 0, 0];
}
CACHE[str] = cached;
}
return cached.slice();
}
/**
* Add two or more colors
*/
export function add(color1, ...colors) {
let result = color1.slice();
for (let i = 0; i < 3; i++) {
for (let j = 0; j < colors.length; j++) {
result[i] += colors[j][i];
}
}
return result;
}
/**
* Add two or more colors, MODIFIES FIRST ARGUMENT
*/
export function add_(color1, ...colors) {
for (let i = 0; i < 3; i++) {
for (let j = 0; j < colors.length; j++) {
color1[i] += colors[j][i];
}
}
return color1;
}
/**
* Multiply (mix) two or more colors
*/
export function multiply(color1, ...colors) {
let result = color1.slice();
for (let i = 0; i < 3; i++) {
for (let j = 0; j < colors.length; j++) {
result[i] *= colors[j][i] / 255;
}
result[i] = Math.round(result[i]);
}
return result;
}
/**
* Multiply (mix) two or more colors, MODIFIES FIRST ARGUMENT
*/
export function multiply_(color1, ...colors) {
for (let i = 0; i < 3; i++) {
for (let j = 0; j < colors.length; j++) {
color1[i] *= colors[j][i] / 255;
}
color1[i] = Math.round(color1[i]);
}
return color1;
}
/**
* Interpolate (blend) two colors with a given factor
*/
export function interpolate(color1, color2, factor = 0.5) {
let result = color1.slice();
for (let i = 0; i < 3; i++) {
result[i] = Math.round(result[i] + factor * (color2[i] - color1[i]));
}
return result;
}
export const lerp = interpolate;
/**
* Interpolate (blend) two colors with a given factor in HSL mode
*/
export function interpolateHSL(color1, color2, factor = 0.5) {
let hsl1 = rgb2hsl(color1);
let hsl2 = rgb2hsl(color2);
for (let i = 0; i < 3; i++) {
hsl1[i] += factor * (hsl2[i] - hsl1[i]);
}
return hsl2rgb(hsl1);
}
export const lerpHSL = interpolateHSL;
/**
* Create a new random color based on this one
* @param color
* @param diff Set of standard deviations
*/
export function randomize(color, diff) {
if (!(diff instanceof Array)) {
diff = Math.round(RNG.getNormal(0, diff));
}
let result = color.slice();
for (let i = 0; i < 3; i++) {
result[i] += (diff instanceof Array ? Math.round(RNG.getNormal(0, diff[i])) : diff);
}
return result;
}
/**
* Converts an RGB color value to HSL. Expects 0..255 inputs, produces 0..1 outputs.
*/
export function rgb2hsl(color) {
let r = color[0] / 255;
let g = color[1] / 255;
let b = color[2] / 255;
let max = Math.max(r, g, b), min = Math.min(r, g, b);
let h = 0, s, l = (max + min) / 2;
if (max == min) {
s = 0; // achromatic
}
else {
let d = max - min;
s = (l > 0.5 ? d / (2 - max - min) : d / (max + min));
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h /= 6;
}
return [h, s, l];
}
function hue2rgb(p, q, t) {
if (t < 0)
t += 1;
if (t > 1)
t -= 1;
if (t < 1 / 6)
return p + (q - p) * 6 * t;
if (t < 1 / 2)
return q;
if (t < 2 / 3)
return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
/**
* Converts an HSL color value to RGB. Expects 0..1 inputs, produces 0..255 outputs.
*/
export function hsl2rgb(color) {
let l = color[2];
if (color[1] == 0) {
l = Math.round(l * 255);
return [l, l, l];
}
else {
let s = color[1];
let q = (l < 0.5 ? l * (1 + s) : l + s - l * s);
let p = 2 * l - q;
let r = hue2rgb(p, q, color[0] + 1 / 3);
let g = hue2rgb(p, q, color[0]);
let b = hue2rgb(p, q, color[0] - 1 / 3);
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
}
export function toRGB(color) {
let clamped = color.map(x => clamp(x, 0, 255));
return `rgb(${clamped.join(",")})`;
}
export function toHex(color) {
let clamped = color.map(x => clamp(x, 0, 255).toString(16).padStart(2, "0"));
return `#${clamped.join("")}`;
}
const CACHE = {
"black": [0, 0, 0],
"navy": [0, 0, 128],
"darkblue": [0, 0, 139],
"mediumblue": [0, 0, 205],
"blue": [0, 0, 255],
"darkgreen": [0, 100, 0],
"green": [0, 128, 0],
"teal": [0, 128, 128],
"darkcyan": [0, 139, 139],
"deepskyblue": [0, 191, 255],
"darkturquoise": [0, 206, 209],
"mediumspringgreen": [0, 250, 154],
"lime": [0, 255, 0],
"springgreen": [0, 255, 127],
"aqua": [0, 255, 255],
"cyan": [0, 255, 255],
"midnightblue": [25, 25, 112],
"dodgerblue": [30, 144, 255],
"forestgreen": [34, 139, 34],
"seagreen": [46, 139, 87],
"darkslategray": [47, 79, 79],
"darkslategrey": [47, 79, 79],
"limegreen": [50, 205, 50],
"mediumseagreen": [60, 179, 113],
"turquoise": [64, 224, 208],
"royalblue": [65, 105, 225],
"steelblue": [70, 130, 180],
"darkslateblue": [72, 61, 139],
"mediumturquoise": [72, 209, 204],
"indigo": [75, 0, 130],
"darkolivegreen": [85, 107, 47],
"cadetblue": [95, 158, 160],
"cornflowerblue": [100, 149, 237],
"mediumaquamarine": [102, 205, 170],
"dimgray": [105, 105, 105],
"dimgrey": [105, 105, 105],
"slateblue": [106, 90, 205],
"olivedrab": [107, 142, 35],
"slategray": [112, 128, 144],
"slategrey": [112, 128, 144],
"lightslategray": [119, 136, 153],
"lightslategrey": [119, 136, 153],
"mediumslateblue": [123, 104, 238],
"lawngreen": [124, 252, 0],
"chartreuse": [127, 255, 0],
"aquamarine": [127, 255, 212],
"maroon": [128, 0, 0],
"purple": [128, 0, 128],
"olive": [128, 128, 0],
"gray": [128, 128, 128],
"grey": [128, 128, 128],
"skyblue": [135, 206, 235],
"lightskyblue": [135, 206, 250],
"blueviolet": [138, 43, 226],
"darkred": [139, 0, 0],
"darkmagenta": [139, 0, 139],
"saddlebrown": [139, 69, 19],
"darkseagreen": [143, 188, 143],
"lightgreen": [144, 238, 144],
"mediumpurple": [147, 112, 216],
"darkviolet": [148, 0, 211],
"palegreen": [152, 251, 152],
"darkorchid": [153, 50, 204],
"yellowgreen": [154, 205, 50],
"sienna": [160, 82, 45],
"brown": [165, 42, 42],
"darkgray": [169, 169, 169],
"darkgrey": [169, 169, 169],
"lightblue": [173, 216, 230],
"greenyellow": [173, 255, 47],
"paleturquoise": [175, 238, 238],
"lightsteelblue": [176, 196, 222],
"powderblue": [176, 224, 230],
"firebrick": [178, 34, 34],
"darkgoldenrod": [184, 134, 11],
"mediumorchid": [186, 85, 211],
"rosybrown": [188, 143, 143],
"darkkhaki": [189, 183, 107],
"silver": [192, 192, 192],
"mediumvioletred": [199, 21, 133],
"indianred": [205, 92, 92],
"peru": [205, 133, 63],
"chocolate": [210, 105, 30],
"tan": [210, 180, 140],
"lightgray": [211, 211, 211],
"lightgrey": [211, 211, 211],
"palevioletred": [216, 112, 147],
"thistle": [216, 191, 216],
"orchid": [218, 112, 214],
"goldenrod": [218, 165, 32],
"crimson": [220, 20, 60],
"gainsboro": [220, 220, 220],
"plum": [221, 160, 221],
"burlywood": [222, 184, 135],
"lightcyan": [224, 255, 255],
"lavender": [230, 230, 250],
"darksalmon": [233, 150, 122],
"violet": [238, 130, 238],
"palegoldenrod": [238, 232, 170],
"lightcoral": [240, 128, 128],
"khaki": [240, 230, 140],
"aliceblue": [240, 248, 255],
"honeydew": [240, 255, 240],
"azure": [240, 255, 255],
"sandybrown": [244, 164, 96],
"wheat": [245, 222, 179],
"beige": [245, 245, 220],
"whitesmoke": [245, 245, 245],
"mintcream": [245, 255, 250],
"ghostwhite": [248, 248, 255],
"salmon": [250, 128, 114],
"antiquewhite": [250, 235, 215],
"linen": [250, 240, 230],
"lightgoldenrodyellow": [250, 250, 210],
"oldlace": [253, 245, 230],
"red": [255, 0, 0],
"fuchsia": [255, 0, 255],
"magenta": [255, 0, 255],
"deeppink": [255, 20, 147],
"orangered": [255, 69, 0],
"tomato": [255, 99, 71],
"hotpink": [255, 105, 180],
"coral": [255, 127, 80],
"darkorange": [255, 140, 0],
"lightsalmon": [255, 160, 122],
"orange": [255, 165, 0],
"lightpink": [255, 182, 193],
"pink": [255, 192, 203],
"gold": [255, 215, 0],
"peachpuff": [255, 218, 185],
"navajowhite": [255, 222, 173],
"moccasin": [255, 228, 181],
"bisque": [255, 228, 196],
"mistyrose": [255, 228, 225],
"blanchedalmond": [255, 235, 205],
"papayawhip": [255, 239, 213],
"lavenderblush": [255, 240, 245],
"seashell": [255, 245, 238],
"cornsilk": [255, 248, 220],
"lemonchiffon": [255, 250, 205],
"floralwhite": [255, 250, 240],
"snow": [255, 250, 250],
"yellow": [255, 255, 0],
"lightyellow": [255, 255, 224],
"ivory": [255, 255, 240],
"white": [255, 255, 255]
};