change how palette gets sent to worker thread
This commit is contained in:
parent
7e38ecd6f7
commit
68ae99b4e0
|
@ -2,21 +2,14 @@
|
|||
* Palette
|
||||
*/
|
||||
|
||||
export type ColorIndex = 0 | 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;
|
||||
export type Color = string;
|
||||
|
||||
|
||||
class Palette {
|
||||
length: number;
|
||||
rgb: Uint8Array;
|
||||
colors: Array<Color>;
|
||||
abgr: Uint32Array;
|
||||
fl: Array<number>;
|
||||
length;
|
||||
rgb;
|
||||
colors;
|
||||
abgr;
|
||||
fl;
|
||||
|
||||
constructor(colors: Array) {
|
||||
constructor(colors) {
|
||||
this.length = colors.length;
|
||||
this.rgb = new Uint8Array(this.length * 3);
|
||||
this.colors = new Array(this.length);
|
||||
|
@ -42,7 +35,7 @@ class Palette {
|
|||
* @param color Index of color in palette
|
||||
* @return dark True if color is dark
|
||||
*/
|
||||
isDark(color: number) {
|
||||
isDark(color) {
|
||||
color *= 3;
|
||||
const r = this.rgb[color++];
|
||||
const g = this.rgb[color++];
|
||||
|
@ -59,10 +52,10 @@ class Palette {
|
|||
* @return index of color
|
||||
*/
|
||||
getIndexOfColor(
|
||||
r: number,
|
||||
g: number,
|
||||
b: number,
|
||||
): ColorIndex {
|
||||
r,
|
||||
g,
|
||||
b,
|
||||
) {
|
||||
const { rgb } = this;
|
||||
let i = rgb.length / 3;
|
||||
while (i > 0) {
|
||||
|
@ -86,10 +79,10 @@ class Palette {
|
|||
* @return index of color
|
||||
*/
|
||||
getClosestIndexOfColor(
|
||||
r: number,
|
||||
g: number,
|
||||
b: number,
|
||||
): ColorIndex {
|
||||
r,
|
||||
g,
|
||||
b,
|
||||
) {
|
||||
const { rgb } = this;
|
||||
let i = rgb.length / 3;
|
||||
let closestIndex = 0;
|
||||
|
@ -113,10 +106,10 @@ class Palette {
|
|||
* @param chunkBuffer Buffer of indexed pixels
|
||||
* @return ABRG Buffer
|
||||
*/
|
||||
buffer2ABGR(chunkBuffer: Buffer): Uint32Array {
|
||||
buffer2ABGR(chunkBuffer) {
|
||||
const { length } = chunkBuffer;
|
||||
const colors = new Uint32Array(length);
|
||||
let value: number;
|
||||
let value;
|
||||
const buffer = chunkBuffer;
|
||||
|
||||
let pos = 0;
|
||||
|
@ -132,11 +125,11 @@ class Palette {
|
|||
* @param chunkBuffer Buffer of indexed pixels
|
||||
* @return RGB Buffer
|
||||
*/
|
||||
buffer2RGB(chunkBuffer: Buffer): Uint8Array {
|
||||
buffer2RGB(chunkBuffer) {
|
||||
const { length } = chunkBuffer;
|
||||
const colors = new Uint8Array(length * 3);
|
||||
let color: number;
|
||||
let value: number;
|
||||
let color;
|
||||
let value;
|
||||
const buffer = chunkBuffer;
|
||||
|
||||
let c = 0;
|
||||
|
@ -157,7 +150,7 @@ class Palette {
|
|||
* @param length Length of needed Buffer
|
||||
* @return RGB Buffer of wanted size with just one color
|
||||
*/
|
||||
oneColorBuffer(color: ColorIndex, length: number) {
|
||||
oneColorBuffer(color, length) {
|
||||
const buffer = new Uint8Array(length * 3);
|
||||
const r = this.rgb[color * 3];
|
||||
const g = this.rgb[color * 3 + 1];
|
||||
|
@ -173,7 +166,7 @@ class Palette {
|
|||
}
|
||||
}
|
||||
|
||||
export const COLORS_RGB: Uint8Array = new Uint8Array([
|
||||
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
|
||||
|
@ -209,9 +202,9 @@ export const COLORS_RGB: Uint8Array = new Uint8Array([
|
|||
]);
|
||||
|
||||
export const COLORS_AMOUNT = COLORS_RGB.length / 3;
|
||||
export const COLORS: Array<Color> = new Array(COLORS_AMOUNT);
|
||||
export const COLORS_ABGR: Uint32Array = new Uint32Array(COLORS_AMOUNT);
|
||||
export const TRANSPARENT: ColorIndex = 0;
|
||||
export const COLORS = new Array(COLORS_AMOUNT);
|
||||
export const COLORS_ABGR = new Uint32Array(COLORS_AMOUNT);
|
||||
export const TRANSPARENT = 0;
|
||||
|
||||
|
||||
export default Palette;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
import sharp from 'sharp';
|
||||
import fs from 'fs';
|
||||
|
||||
import Palette from './Palette';
|
||||
import { getMaxTiledZoom } from './utils';
|
||||
import { TILE_SIZE, TILE_ZOOM_LEVEL } from './constants';
|
||||
|
||||
|
@ -113,22 +114,22 @@ function tileFileName(canvasTileFolder, cell) {
|
|||
}
|
||||
|
||||
/*
|
||||
* @param canvasSize dimension of the canvas (pixels width/height)
|
||||
* @param redisClient redis instance
|
||||
* @param canvasId id of the canvas
|
||||
* @param canvas canvas data
|
||||
* @param canvasTileFolder root folder where to save tiles
|
||||
* @param palette Palette to use
|
||||
* @param cell tile to create [x, y]
|
||||
* @return true if successfully created tile, false if tile empty
|
||||
*/
|
||||
export async function createZoomTileFromChunk(
|
||||
redisClient,
|
||||
canvasSize,
|
||||
canvasId,
|
||||
canvas,
|
||||
canvasTileFolder,
|
||||
palette,
|
||||
cell,
|
||||
) {
|
||||
const palette = new Palette(canvas.colors);
|
||||
const canvasSize = canvas.size;
|
||||
const [x, y] = cell;
|
||||
const maxTiledZoom = getMaxTiledZoom(canvasSize);
|
||||
const tileRGBBuffer = new Uint8Array(
|
||||
|
@ -166,6 +167,7 @@ export async function createZoomTileFromChunk(
|
|||
});
|
||||
|
||||
const filename = tileFileName(canvasTileFolder, [maxTiledZoom - 1, x, y]);
|
||||
try {
|
||||
await sharp(Buffer.from(tileRGBBuffer.buffer), {
|
||||
raw: {
|
||||
width: TILE_SIZE * TILE_ZOOM_LEVEL,
|
||||
|
@ -176,6 +178,12 @@ export async function createZoomTileFromChunk(
|
|||
.resize(TILE_SIZE)
|
||||
.png({ options: { compressionLevel: 6 } })
|
||||
.toFile(filename);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Tiling: Error on createZoomTileFromChunk:\n${error.message}`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
console.log(
|
||||
// eslint-disable-next-line max-len
|
||||
`Tiling: Created Tile ${filename} with ${na.length} empty chunks in ${Date.now() - startTime}ms`,
|
||||
|
@ -186,16 +194,17 @@ export async function createZoomTileFromChunk(
|
|||
}
|
||||
|
||||
/*
|
||||
* @param canvas canvas data
|
||||
* @param canvasTileFolder root folder where to save tiles
|
||||
* @param palette Palette to use
|
||||
* @param cell tile to create [z, x, y]
|
||||
* @return trie if successfully created tile, false if tile empty
|
||||
*/
|
||||
export async function createZoomedTile(
|
||||
canvas,
|
||||
canvasTileFolder,
|
||||
palette,
|
||||
cell,
|
||||
) {
|
||||
const palette = new Palette(canvas.colors);
|
||||
const tileRGBBuffer = new Uint8Array(
|
||||
TILE_SIZE * TILE_SIZE * TILE_ZOOM_LEVEL * TILE_ZOOM_LEVEL * 3,
|
||||
);
|
||||
|
@ -211,8 +220,15 @@ export async function createZoomedTile(
|
|||
na.push([dx, dy]);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
const chunk = await sharp(chunkfile).removeAlpha().raw().toBuffer();
|
||||
addRGBSubtiletoTile(TILE_ZOOM_LEVEL, [dx, dy], chunk, tileRGBBuffer);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
// eslint-disable-next-line max-len
|
||||
`Tiling: Error on createZoomedTile on chunk ${chunkfile}:\n${error.message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,6 +238,7 @@ export async function createZoomedTile(
|
|||
});
|
||||
|
||||
const filename = tileFileName(canvasTileFolder, [z, x, y]);
|
||||
try {
|
||||
await sharp(
|
||||
Buffer.from(
|
||||
tileRGBBuffer.buffer,
|
||||
|
@ -233,6 +250,12 @@ export async function createZoomedTile(
|
|||
},
|
||||
},
|
||||
).resize(TILE_SIZE).toFile(filename);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Tiling: Error on createZoomedTile:\n${error.message}`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
console.log(
|
||||
// eslint-disable-next-line max-len
|
||||
`Tiling: Created tile ${filename} with ${na.length} empty subtiles in ${Date.now() - startTime}ms.`,
|
||||
|
@ -247,7 +270,7 @@ export async function createZoomedTile(
|
|||
* @param canvasTileFolder root folder where to save texture
|
||||
* @param palette Palette to use
|
||||
*/
|
||||
export async function createEmptyTile(
|
||||
async function createEmptyTile(
|
||||
canvasTileFolder,
|
||||
palette,
|
||||
) {
|
||||
|
@ -265,6 +288,7 @@ export async function createEmptyTile(
|
|||
tileRGBBuffer[i++] = palette.rgb[2];
|
||||
}
|
||||
const filename = `${canvasTileFolder}/emptytile.png`;
|
||||
try {
|
||||
await sharp(Buffer.from(tileRGBBuffer.buffer), {
|
||||
raw: {
|
||||
width: TILE_SIZE,
|
||||
|
@ -274,6 +298,12 @@ export async function createEmptyTile(
|
|||
})
|
||||
.png({ options: { compressionLevel: 6 } })
|
||||
.toFile(filename);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Tiling: Error on createEmptyTile:\n${error.message}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
console.log(`Tiling: Created empty tile at ${filename}`);
|
||||
}
|
||||
|
||||
|
@ -281,18 +311,18 @@ export async function createEmptyTile(
|
|||
* created 4096x4096 texture of default canvas
|
||||
* @param redisClient redis instance
|
||||
* @param canvasId numberical Id of canvas
|
||||
* @param canvasSize size of canvas
|
||||
* @param canvas canvas data
|
||||
* @param canvasTileFolder root folder where to save texture
|
||||
* @param palette Palette to use
|
||||
*
|
||||
*/
|
||||
export async function createTexture(
|
||||
redisClient,
|
||||
canvasId,
|
||||
canvasSize,
|
||||
canvas,
|
||||
canvasTileFolder,
|
||||
palette,
|
||||
) {
|
||||
const palette = new Palette(canvas.colors);
|
||||
const canvasSize = canvas.size;
|
||||
// dont create textures larger than 4096
|
||||
const targetSize = Math.min(canvasSize, 4096);
|
||||
const amount = targetSize / TILE_SIZE;
|
||||
|
@ -310,8 +340,15 @@ export async function createTexture(
|
|||
na.push([dx, dy]);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
chunk = await sharp(chunkfile).removeAlpha().raw().toBuffer();
|
||||
addRGBSubtiletoTile(amount, [dx, dy], chunk, textureBuffer);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
// eslint-disable-next-line max-len
|
||||
`Tiling: Error on createTexture in chunk ${chunkfile}:\n${error.message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -339,6 +376,7 @@ export async function createTexture(
|
|||
});
|
||||
|
||||
const filename = `${canvasTileFolder}/texture.png`;
|
||||
try {
|
||||
await sharp(
|
||||
Buffer.from(textureBuffer.buffer), {
|
||||
raw: {
|
||||
|
@ -348,6 +386,12 @@ export async function createTexture(
|
|||
},
|
||||
},
|
||||
).toFile(filename);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Tiling: Error on createTexture:\n${error.message}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
console.log(
|
||||
`Tiling: Created texture in ${(Date.now() - startTime) / 1000}s.`,
|
||||
);
|
||||
|
@ -356,24 +400,24 @@ export async function createTexture(
|
|||
/*
|
||||
* Create all tiles
|
||||
* @param redisClient redis instance
|
||||
* @param canvasSize dimension of the canvas (pixels width/height)
|
||||
* @param canvasId id of the canvas
|
||||
* @param canvasTileFolder root foler where to save tiles
|
||||
* @param palette Palette of canvas
|
||||
* @param canvas canvas data
|
||||
* @param canvasTileFolder folder for tiles
|
||||
* @param force overwrite existing tiles
|
||||
*/
|
||||
export async function initializeTiles(
|
||||
redisClient,
|
||||
canvasSize,
|
||||
canvasId,
|
||||
canvas,
|
||||
canvasTileFolder,
|
||||
palette,
|
||||
force = false,
|
||||
) {
|
||||
console.log(
|
||||
`Tiling: Initializing tiles in ${canvasTileFolder}, forceint = ${force}`,
|
||||
);
|
||||
const startTime = Date.now();
|
||||
const palette = new Palette(canvas.colors);
|
||||
const canvasSize = canvas.size;
|
||||
const maxTiledZoom = getMaxTiledZoom(canvasSize);
|
||||
// empty tile
|
||||
await createEmptyTile(canvasTileFolder, palette);
|
||||
|
@ -440,9 +484,8 @@ export async function initializeTiles(
|
|||
await createTexture(
|
||||
redisClient,
|
||||
canvasId,
|
||||
canvasSize,
|
||||
canvas,
|
||||
canvasTileFolder,
|
||||
palette,
|
||||
);
|
||||
//--
|
||||
console.log(
|
||||
|
|
|
@ -9,7 +9,6 @@ import { Worker } from 'worker_threads';
|
|||
import logger from './logger';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import canvases from './canvases.json';
|
||||
import Palette from './Palette';
|
||||
import RedisCanvas from '../data/models/RedisCanvas';
|
||||
|
||||
import { TILE_FOLDER } from './config';
|
||||
|
@ -29,7 +28,6 @@ const worker = new Worker('./workers/tilewriter.js');
|
|||
|
||||
class CanvasUpdater {
|
||||
TileLoadingQueues;
|
||||
palette;
|
||||
id;
|
||||
canvas;
|
||||
firstZoomtileWidth;
|
||||
|
@ -42,7 +40,6 @@ class CanvasUpdater {
|
|||
this.id = id;
|
||||
this.canvas = canvases[id];
|
||||
this.canvasTileFolder = `${TILE_FOLDER}/${id}`;
|
||||
this.palette = new Palette(this.canvas.colors);
|
||||
this.firstZoomtileWidth = this.canvas.size / TILE_SIZE / TILE_ZOOM_LEVEL;
|
||||
this.maxTiledZoom = getMaxTiledZoom(this.canvas.size);
|
||||
this.startReloadingLoops();
|
||||
|
@ -65,10 +62,9 @@ class CanvasUpdater {
|
|||
worker.postMessage({
|
||||
task: 'createZoomTileFromChunk',
|
||||
args: [
|
||||
this.canvas.size,
|
||||
this.id,
|
||||
this.canvas,
|
||||
this.canvasTileFolder,
|
||||
this.palette,
|
||||
[cx, cy],
|
||||
],
|
||||
});
|
||||
|
@ -76,8 +72,8 @@ class CanvasUpdater {
|
|||
worker.postMessage({
|
||||
task: 'createZoomedTile',
|
||||
args: [
|
||||
this.canvas,
|
||||
this.canvasTileFolder,
|
||||
this.palette,
|
||||
[zoom, cx, cy],
|
||||
],
|
||||
});
|
||||
|
@ -88,9 +84,8 @@ class CanvasUpdater {
|
|||
task: 'createTexture',
|
||||
args: [
|
||||
this.id,
|
||||
this.canvas.size,
|
||||
this.canvas,
|
||||
this.canvasTileFolder,
|
||||
this.palette,
|
||||
],
|
||||
});
|
||||
} else {
|
||||
|
@ -126,10 +121,9 @@ class CanvasUpdater {
|
|||
worker.postMessage({
|
||||
task: 'initializeTiles',
|
||||
args: [
|
||||
this.canvas.size,
|
||||
this.id,
|
||||
this.canvas,
|
||||
this.canvasTileFolder,
|
||||
this.palette,
|
||||
false,
|
||||
],
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user