save in webp
adjust Tile creation
This commit is contained in:
parent
c8409c6e5f
commit
61ec34d7b4
157
src/core/Tile.js
157
src/core/Tile.js
|
@ -241,7 +241,7 @@ function addIndexedSubtiletoTile(
|
||||||
*/
|
*/
|
||||||
function tileFileName(canvasTileFolder, cell) {
|
function tileFileName(canvasTileFolder, cell) {
|
||||||
const [z, x, y] = cell;
|
const [z, x, y] = cell;
|
||||||
const filename = `${canvasTileFolder}/${z}/${x}/${y}.png`;
|
const filename = `${canvasTileFolder}/${z}/${x}/${y}.webp`;
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,24 +271,17 @@ export async function createZoomTileFromChunk(
|
||||||
const xabs = x * TILE_ZOOM_LEVEL;
|
const xabs = x * TILE_ZOOM_LEVEL;
|
||||||
const yabs = y * TILE_ZOOM_LEVEL;
|
const yabs = y * TILE_ZOOM_LEVEL;
|
||||||
const na = [];
|
const na = [];
|
||||||
for (let dy = 0; dy < TILE_ZOOM_LEVEL; dy += 1) {
|
|
||||||
for (let dx = 0; dx < TILE_ZOOM_LEVEL; dx += 1) {
|
const prom = async (dx, dy) => {
|
||||||
let chunk = null;
|
try {
|
||||||
try {
|
const chunk = await RedisCanvas.getChunk(
|
||||||
chunk = await RedisCanvas.getChunk(
|
canvasId,
|
||||||
canvasId,
|
xabs + dx,
|
||||||
xabs + dx,
|
yabs + dy,
|
||||||
yabs + dy,
|
);
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
`Tiling: Failed to get Chunk ch:${canvasId}:${xabs + dx}${yabs + dy} with error ${error.message}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!chunk || !chunk.length) {
|
if (!chunk || !chunk.length) {
|
||||||
na.push([dx, dy]);
|
na.push([dx, dy]);
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
addIndexedSubtiletoTile(
|
addIndexedSubtiletoTile(
|
||||||
palette,
|
palette,
|
||||||
|
@ -297,8 +290,22 @@ export async function createZoomTileFromChunk(
|
||||||
chunk,
|
chunk,
|
||||||
tileRGBBuffer,
|
tileRGBBuffer,
|
||||||
);
|
);
|
||||||
|
} catch (error) {
|
||||||
|
na.push([dx, dy]);
|
||||||
|
console.error(
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
`Tiling: Failed to get Chunk ch:${canvasId}:${xabs + dx}${yabs + dy} with error ${error.message}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const promises = [];
|
||||||
|
for (let dy = 0; dy < TILE_ZOOM_LEVEL; dy += 1) {
|
||||||
|
for (let dx = 0; dx < TILE_ZOOM_LEVEL; dx += 1) {
|
||||||
|
promises.push(prom(dx, dy));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await Promise.all(promises);
|
||||||
|
|
||||||
if (na.length !== TILE_ZOOM_LEVEL * TILE_ZOOM_LEVEL) {
|
if (na.length !== TILE_ZOOM_LEVEL * TILE_ZOOM_LEVEL) {
|
||||||
na.forEach((element) => {
|
na.forEach((element) => {
|
||||||
|
@ -313,7 +320,7 @@ export async function createZoomTileFromChunk(
|
||||||
|
|
||||||
const filename = tileFileName(canvasTileFolder, [maxTiledZoom - 1, x, y]);
|
const filename = tileFileName(canvasTileFolder, [maxTiledZoom - 1, x, y]);
|
||||||
try {
|
try {
|
||||||
await sharp(Buffer.from(tileRGBBuffer.buffer), {
|
await sharp(tileRGBBuffer, {
|
||||||
raw: {
|
raw: {
|
||||||
width: TILE_SIZE * TILE_ZOOM_LEVEL,
|
width: TILE_SIZE * TILE_ZOOM_LEVEL,
|
||||||
height: TILE_SIZE * TILE_ZOOM_LEVEL,
|
height: TILE_SIZE * TILE_ZOOM_LEVEL,
|
||||||
|
@ -321,7 +328,7 @@ export async function createZoomTileFromChunk(
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.resize(TILE_SIZE)
|
.resize(TILE_SIZE)
|
||||||
.png({ options: { compressionLevel: 6 } })
|
.webp({ quality: 100, smartSubsample: true })
|
||||||
.toFile(filename);
|
.toFile(filename);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
console.error(
|
||||||
|
@ -361,7 +368,7 @@ export async function createZoomedTile(
|
||||||
|
|
||||||
const prom = async (dx, dy) => {
|
const prom = async (dx, dy) => {
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
const chunkfile = `${canvasTileFolder}/${z + 1}/${x * TILE_ZOOM_LEVEL + dx}/${y * TILE_ZOOM_LEVEL + dy}.png`;
|
const chunkfile = `${canvasTileFolder}/${z + 1}/${x * TILE_ZOOM_LEVEL + dx}/${y * TILE_ZOOM_LEVEL + dy}.webp`;
|
||||||
try {
|
try {
|
||||||
if (!fs.existsSync(chunkfile)) {
|
if (!fs.existsSync(chunkfile)) {
|
||||||
na.push([dx, dy]);
|
na.push([dx, dy]);
|
||||||
|
@ -404,17 +411,15 @@ export async function createZoomedTile(
|
||||||
|
|
||||||
const filename = tileFileName(canvasTileFolder, [z, x, y]);
|
const filename = tileFileName(canvasTileFolder, [z, x, y]);
|
||||||
try {
|
try {
|
||||||
await sharp(
|
await sharp(tileRGBBuffer, {
|
||||||
Buffer.from(
|
raw: {
|
||||||
tileRGBBuffer.buffer,
|
width: TILE_SIZE,
|
||||||
), {
|
height: TILE_SIZE,
|
||||||
raw: {
|
channels: 3,
|
||||||
width: TILE_SIZE,
|
|
||||||
height: TILE_SIZE,
|
|
||||||
channels: 3,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
).toFile(filename);
|
})
|
||||||
|
.webp({ quality: 100, smartSubsample: true })
|
||||||
|
.toFile(filename);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
console.error(
|
||||||
`Tiling: Error on createZoomedTile: ${error.message}`,
|
`Tiling: Error on createZoomedTile: ${error.message}`,
|
||||||
|
@ -452,16 +457,16 @@ async function createEmptyTile(
|
||||||
// eslint-disable-next-line prefer-destructuring
|
// eslint-disable-next-line prefer-destructuring
|
||||||
tileRGBBuffer[i++] = palette.rgb[2];
|
tileRGBBuffer[i++] = palette.rgb[2];
|
||||||
}
|
}
|
||||||
const filename = `${canvasTileFolder}/emptytile.png`;
|
const filename = `${canvasTileFolder}/emptytile.webp`;
|
||||||
try {
|
try {
|
||||||
await sharp(Buffer.from(tileRGBBuffer.buffer), {
|
await sharp(tileRGBBuffer, {
|
||||||
raw: {
|
raw: {
|
||||||
width: TILE_SIZE,
|
width: TILE_SIZE,
|
||||||
height: TILE_SIZE,
|
height: TILE_SIZE,
|
||||||
channels: 3,
|
channels: 3,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.png({ options: { compressionLevel: 6 } })
|
.webp({ quality: 100, smartSubsample: true })
|
||||||
.toFile(filename);
|
.toFile(filename);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
console.error(
|
||||||
|
@ -494,45 +499,36 @@ export async function createTexture(
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
const na = [];
|
const na = [];
|
||||||
if (targetSize !== canvasSize) {
|
|
||||||
for (let dy = 0; dy < amount; dy += 1) {
|
const prom = (targetSize !== canvasSize)
|
||||||
for (let dx = 0; dx < amount; dx += 1) {
|
? async (dx, dy) => {
|
||||||
let chunk = null;
|
const chunkfile = `${canvasTileFolder}/${zoom}/${dx}/${dy}.webp`;
|
||||||
const chunkfile = `${canvasTileFolder}/${zoom}/${dx}/${dy}.png`;
|
try {
|
||||||
if (!fs.existsSync(chunkfile)) {
|
if (!fs.existsSync(chunkfile)) {
|
||||||
na.push([dx, dy]);
|
na.push([dx, dy]);
|
||||||
continue;
|
return;
|
||||||
}
|
|
||||||
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}: ${error.message}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
const chunk = await sharp(chunkfile).removeAlpha().raw().toBuffer();
|
||||||
|
addRGBSubtiletoTile(amount, [dx, dy], chunk, textureBuffer);
|
||||||
|
} catch (error) {
|
||||||
|
na.push([dx, dy]);
|
||||||
|
console.error(
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
`Tiling: Error on createTexture in chunk ${chunkfile}: ${error.message}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
: async (dx, dy) => {
|
||||||
for (let dy = 0; dy < amount; dy += 1) {
|
try {
|
||||||
for (let dx = 0; dx < amount; dx += 1) {
|
|
||||||
let chunk = null;
|
let chunk = null;
|
||||||
try {
|
chunk = await RedisCanvas.getChunk(
|
||||||
chunk = await RedisCanvas.getChunk(
|
canvasId,
|
||||||
canvasId,
|
dx,
|
||||||
dx,
|
dy,
|
||||||
dy,
|
);
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
`Tiling: Failed to get Chunk ch:${canvasId}:${dx}${dy} with error ${error.message}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!chunk || !chunk.length) {
|
if (!chunk || !chunk.length) {
|
||||||
na.push([dx, dy]);
|
na.push([dx, dy]);
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
addIndexedSubtiletoTile(
|
addIndexedSubtiletoTile(
|
||||||
palette,
|
palette,
|
||||||
|
@ -541,25 +537,36 @@ export async function createTexture(
|
||||||
chunk,
|
chunk,
|
||||||
textureBuffer,
|
textureBuffer,
|
||||||
);
|
);
|
||||||
|
} catch (error) {
|
||||||
|
na.push([dx, dy]);
|
||||||
|
console.error(
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
`Tiling: Failed to get Chunk ch:${canvasId}:${dx}${dy} with error ${error.message}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const promises = [];
|
||||||
|
for (let dy = 0; dy < amount; dy += 1) {
|
||||||
|
for (let dx = 0; dx < amount; dx += 1) {
|
||||||
|
promises.push(prom(dx, dy));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await Promise.all(promises);
|
||||||
|
|
||||||
na.forEach((element) => {
|
na.forEach((element) => {
|
||||||
deleteSubtilefromTile(TILE_SIZE, palette, amount, element, textureBuffer);
|
deleteSubtilefromTile(TILE_SIZE, palette, amount, element, textureBuffer);
|
||||||
});
|
});
|
||||||
|
|
||||||
const filename = `${canvasTileFolder}/texture.png`;
|
const filename = `${canvasTileFolder}/texture.webp`;
|
||||||
try {
|
try {
|
||||||
await sharp(
|
await sharp(textureBuffer, {
|
||||||
Buffer.from(textureBuffer.buffer), {
|
raw: {
|
||||||
raw: {
|
width: targetSize,
|
||||||
width: targetSize,
|
height: targetSize,
|
||||||
height: targetSize,
|
channels: 3,
|
||||||
channels: 3,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
).toFile(filename);
|
}).toFile(filename);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
console.error(
|
||||||
`Tiling: Error on createTexture: ${error.message}`,
|
`Tiling: Error on createTexture: ${error.message}`,
|
||||||
|
@ -605,7 +612,7 @@ export async function initializeTiles(
|
||||||
const tileDir = `${canvasTileFolder}/${zoom}/${cx}`;
|
const tileDir = `${canvasTileFolder}/${zoom}/${cx}`;
|
||||||
if (!fs.existsSync(tileDir)) fs.mkdirSync(tileDir);
|
if (!fs.existsSync(tileDir)) fs.mkdirSync(tileDir);
|
||||||
for (let cy = 0; cy < maxBase; cy += 1) {
|
for (let cy = 0; cy < maxBase; cy += 1) {
|
||||||
const filename = `${canvasTileFolder}/${zoom}/${cx}/${cy}.png`;
|
const filename = `${canvasTileFolder}/${zoom}/${cx}/${cy}.webp`;
|
||||||
if (force || !fs.existsSync(filename)) {
|
if (force || !fs.existsSync(filename)) {
|
||||||
const ret = await createZoomTileFromChunk(
|
const ret = await createZoomTileFromChunk(
|
||||||
canvasId,
|
canvasId,
|
||||||
|
@ -634,7 +641,7 @@ export async function initializeTiles(
|
||||||
const tileDir = `${canvasTileFolder}/${zoom}/${cx}`;
|
const tileDir = `${canvasTileFolder}/${zoom}/${cx}`;
|
||||||
if (!fs.existsSync(tileDir)) fs.mkdirSync(tileDir);
|
if (!fs.existsSync(tileDir)) fs.mkdirSync(tileDir);
|
||||||
for (let cy = 0; cy < maxZ; cy += 1) {
|
for (let cy = 0; cy < maxZ; cy += 1) {
|
||||||
const filename = `${canvasTileFolder}/${zoom}/${cx}/${cy}.png`;
|
const filename = `${canvasTileFolder}/${zoom}/${cx}/${cy}.webp`;
|
||||||
if (force || !fs.existsSync(filename)) {
|
if (force || !fs.existsSync(filename)) {
|
||||||
const ret = await createZoomedTile(
|
const ret = await createZoomedTile(
|
||||||
canvas,
|
canvas,
|
||||||
|
|
|
@ -161,7 +161,9 @@ class CanvasUpdater {
|
||||||
}
|
}
|
||||||
for (let c = 0; c < this.maxTiledZoom; c += 1) {
|
for (let c = 0; c < this.maxTiledZoom; c += 1) {
|
||||||
this.TileLoadingQueues.push([]);
|
this.TileLoadingQueues.push([]);
|
||||||
const timeout = (7 ** (this.maxTiledZoom - c - 1)) * 5 * 1000;
|
const invZoom = this.maxTiledZoom - c - 1;
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
const timeout = TILE_ZOOM_LEVEL ** (2 * invZoom + 2) * (6 / TILE_ZOOM_LEVEL ** 2) * 1000;
|
||||||
logger.info(
|
logger.info(
|
||||||
`Tiling: Set interval for zoomlevel ${c} update to ${timeout / 1000}`,
|
`Tiling: Set interval for zoomlevel ${c} update to ${timeout / 1000}`,
|
||||||
);
|
);
|
||||||
|
|
|
@ -51,7 +51,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
const [canvasIdent, canvasId, canvasSize, x, y] = parseHashCoords();
|
const [canvasIdent, canvasId, canvasSize, x, y] = parseHashCoords();
|
||||||
|
|
||||||
const canvasTexture = new THREE.MeshPhongMaterial({
|
const canvasTexture = new THREE.MeshPhongMaterial({
|
||||||
map: new THREE.TextureLoader().load(`./tiles/${canvasId}/texture.png`),
|
map: new THREE.TextureLoader().load(`./tiles/${canvasId}/texture.webp`),
|
||||||
bumpMap: new THREE.TextureLoader().load(`./assets3d/normal${canvasId}.jpg`),
|
bumpMap: new THREE.TextureLoader().load(`./assets3d/normal${canvasId}.jpg`),
|
||||||
bumpScale: 0.02,
|
bumpScale: 0.02,
|
||||||
specularMap: new THREE.TextureLoader()
|
specularMap: new THREE.TextureLoader()
|
||||||
|
|
|
@ -23,12 +23,12 @@ router.use('/', express.static(TILE_FOLDER, {
|
||||||
/*
|
/*
|
||||||
* catch File Not Found: Send empty tile
|
* catch File Not Found: Send empty tile
|
||||||
*/
|
*/
|
||||||
router.use('/:c([0-9]+)/:z([0-9]+)/:x([0-9]+)/:y([0-9]+).png',
|
router.use('/:c([0-9]+)/:z([0-9]+)/:x([0-9]+)/:y([0-9]+).webp',
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const { c: paramC } = req.params;
|
const { c: paramC } = req.params;
|
||||||
const c = parseInt(paramC, 10);
|
const c = parseInt(paramC, 10);
|
||||||
|
|
||||||
const filename = `${TILE_FOLDER}/${c}/emptytile.png`;
|
const filename = `${TILE_FOLDER}/${c}/emptytile.webp`;
|
||||||
if (!fs.existsSync(filename)) {
|
if (!fs.existsSync(filename)) {
|
||||||
res.set({
|
res.set({
|
||||||
'Cache-Control': `public, s-maxage=${24 * 3600}, max-age=${24 * 3600}`,
|
'Cache-Control': `public, s-maxage=${24 * 3600}, max-age=${24 * 3600}`,
|
||||||
|
@ -39,7 +39,7 @@ router.use('/:c([0-9]+)/:z([0-9]+)/:x([0-9]+)/:y([0-9]+).png',
|
||||||
|
|
||||||
res.set({
|
res.set({
|
||||||
'Cache-Control': `public, s-maxage=${2 * 3600}, max-age=${1 * 3600}`,
|
'Cache-Control': `public, s-maxage=${2 * 3600}, max-age=${1 * 3600}`,
|
||||||
'Content-Type': 'image/png',
|
'Content-Type': 'image/webp',
|
||||||
});
|
});
|
||||||
res.status(200);
|
res.status(200);
|
||||||
res.sendFile(filename);
|
res.sendFile(filename);
|
||||||
|
|
|
@ -304,7 +304,7 @@ class ChunkLoader {
|
||||||
const center = [zoom, cx, cy];
|
const center = [zoom, cx, cy];
|
||||||
this.store.dispatch(requestBigChunk(center));
|
this.store.dispatch(requestBigChunk(center));
|
||||||
try {
|
try {
|
||||||
const url = `tiles/${this.canvasId}/${zoom}/${cx}/${cy}.png`;
|
const url = `tiles/${this.canvasId}/${zoom}/${cx}/${cy}.webp`;
|
||||||
const img = await loadImage(url);
|
const img = await loadImage(url);
|
||||||
chunkRGB.fromImage(img);
|
chunkRGB.fromImage(img);
|
||||||
this.store.dispatch(receiveBigChunk(center, chunkRGB));
|
this.store.dispatch(receiveBigChunk(center, chunkRGB));
|
||||||
|
|
Loading…
Reference in New Issue
Block a user