UNPKG

rot-js

Version:

A roguelike toolkit in JavaScript

337 lines (336 loc) 10 kB
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] };