pixelplanet/src/core/Palette.js

210 lines
4.9 KiB
JavaScript

/*
* Palette
*/
class Palette {
length;
rgb;
colors;
abgr;
fl;
constructor(colors) {
this.length = colors.length;
this.rgb = new Uint8Array(this.length * 3);
this.colors = new Array(this.length);
this.abgr = new Uint32Array(this.length);
this.fl = new Array(this.length);
let cnt = 0;
for (let index = 0; index < colors.length; index++) {
const r = colors[index][0];
const g = colors[index][1];
const b = colors[index][2];
this.rgb[cnt++] = r;
this.rgb[cnt++] = g;
this.rgb[cnt++] = b;
this.colors[index] = `rgb(${r}, ${g}, ${b})`;
this.abgr[index] = (0xFF000000) | (b << 16) | (g << 8) | (r);
this.fl[index] = [r / 256, g / 256, b / 256];
}
}
/*
* Check if a color is light (closer to white) or dark (closer to black)
* @param color Index of color in palette
* @return dark True if color is dark
*/
isDark(color) {
color *= 3;
const r = this.rgb[color++];
const g = this.rgb[color++];
const b = this.rgb[color];
const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
return (luminance < 128);
}
/*
* Get last matching color index of RGB color
* @param r r
* @param g g
* @param b b
* @return index of color
*/
getIndexOfColor(
r,
g,
b,
) {
const { rgb } = this;
let i = rgb.length / 3;
while (i > 0) {
i -= 1;
const off = i * 3;
if (rgb[off] === r
&& rgb[off + 1] === g
&& rgb[off + 2] === b
) {
return i;
}
}
return null;
}
/*
* Get closest matching color index of RGB color
* @param r r
* @param g g
* @param b b
* @return index of color
*/
getClosestIndexOfColor(
r,
g,
b,
) {
const { rgb } = this;
let i = rgb.length / 3;
let closestIndex = 0;
let closestDistance = null;
while (i > 0) {
i -= 1;
const off = i * 3;
let distance = (rgb[off] - r) ** 2;
distance += (rgb[off + 1] - g) ** 2;
distance += (rgb[off + 2] - b) ** 2;
if (closestDistance === null || closestDistance > distance) {
closestIndex = i;
closestDistance = distance;
}
}
return closestIndex;
}
/*
* Take a buffer of indexed pixels and output it as ABGR Array
* @param chunkBuffer Buffer of indexed pixels
* @return ABRG Buffer
*/
buffer2ABGR(chunkBuffer) {
const { length } = chunkBuffer;
const colors = new Uint32Array(length);
let value;
let pos = 0;
for (let i = 0; i < length; i++) {
value = (chunkBuffer[i] & 0x3F);
colors[pos++] = this.abgr[value];
}
return colors;
}
/*
* Take a buffer of indexed pixels and output it as RGB Array
* @param chunkBuffer Buffer of indexed pixels
* @return RGB Buffer
*/
buffer2RGB(chunkBuffer) {
const { length } = chunkBuffer;
const colors = new Uint8Array(length * 3);
let color;
let value;
const buffer = chunkBuffer;
let c = 0;
for (let i = 0; i < length; i++) {
value = buffer[i];
color = (value & 0x3F) * 3;
colors[c++] = this.rgb[color++];
colors[c++] = this.rgb[color++];
colors[c++] = this.rgb[color];
}
return colors;
}
/*
* Create a RGB Buffer of a specific size with just one color
* @param color Color Index of color to use
* @param length Length of needed Buffer
* @return RGB Buffer of wanted size with just one color
*/
oneColorBuffer(color, length) {
const buffer = new Uint8Array(length * 3);
const r = this.rgb[color * 3];
const g = this.rgb[color * 3 + 1];
const b = this.rgb[color * 3 + 2];
let pos = 0;
for (let i = 0; i < length; i++) {
buffer[pos++] = r;
buffer[pos++] = g;
buffer[pos++] = b;
}
return buffer;
}
}
export const COLORS_RGB = new Uint8Array([
202, 227, 255, // first color is unset pixel in ocean
255, 255, 255, // second color is unset pixel on land
255, 255, 255, // white
228, 228, 228, // light gray
196, 196, 196, // silver
136, 136, 136, // dark gray
78, 78, 78, // darker gray
0, 0, 0, // black
244, 179, 174, // skin
255, 167, 209, // light pink
255, 84, 178, // pink
255, 101, 101, // peach
229, 0, 0, // red
154, 0, 0, // dark red
254, 164, 96, // light brown
229, 149, 0, // orange
160, 106, 66, // brown
96, 64, 40, // dark brown
245, 223, 176, // sand
255, 248, 137, // khaki
229, 217, 0, // yellow
148, 224, 68, // light green
2, 190, 1, // green
104, 131, 56, // olive
0, 101, 19, // dark green
202, 227, 255, // sky blue
0, 211, 221, // light blue
0, 131, 199, // dark blue
0, 0, 234, // blue
25, 25, 115, // darker blue
207, 110, 228, // light violette
130, 0, 128, // violette
]);
export const COLORS_AMOUNT = COLORS_RGB.length / 3;
export const COLORS = new Array(COLORS_AMOUNT);
export const COLORS_ABGR = new Uint32Array(COLORS_AMOUNT);
export const TRANSPARENT = 0;
export default Palette;