You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tobspr_shapez.io/src/js/game/hud/parts/layer_preview.js

124 lines
4.3 KiB

import { freeCanvas, makeOffscreenBuffer } from "../../../core/buffer_utils";
import { globalConfig } from "../../../core/config";
import { Loader } from "../../../core/loader";
import { Vector } from "../../../core/vector";
import { MapChunkView } from "../../map_chunk_view";
import { THEME } from "../../theme";
import { BaseHUDPart } from "../base_hud_part";
/**
* Helper class which allows peaking through to the wires layer
*/
export class HUDLayerPreview extends BaseHUDPart {
initialize() {
this.initializeCanvas();
this.root.signals.aboutToDestruct.add(() => freeCanvas(this.canvas));
this.root.signals.resized.add(this.initializeCanvas, this);
this.previewOverlay = Loader.getSprite("sprites/wires/wires_preview.png");
}
/**
* (re) initializes the canvas
*/
initializeCanvas() {
if (this.canvas) {
freeCanvas(this.canvas);
delete this.canvas;
delete this.context;
}
// Compute how big the preview should be
this.previewSize = Math.round(
Math.min(1024, Math.min(this.root.gameWidth, this.root.gameHeight) * 0.8)
);
const [canvas, context] = makeOffscreenBuffer(this.previewSize, this.previewSize, {
smooth: true,
label: "layerPeeker",
reusable: true,
});
context.clearRect(0, 0, this.previewSize, this.previewSize);
this.canvas = canvas;
this.context = context;
}
/**
* Prepares the canvas to render at the given worldPos and the given camera scale
*
* @param {Vector} worldPos
* @param {number} scale 1 / zoomLevel
*/
prepareCanvasForPreview(worldPos, scale) {
this.context.clearRect(0, 0, this.previewSize, this.previewSize);
this.context.fillStyle = THEME.map.wires.previewColor;
this.context.fillRect(0, 0, this.previewSize, this.previewSize);
const dimensions = scale * this.previewSize;
const startWorldX = worldPos.x - dimensions / 2;
const startWorldY = worldPos.y - dimensions / 2;
const startTileX = Math.floor(startWorldX / globalConfig.tileSize);
const startTileY = Math.floor(startWorldY / globalConfig.tileSize);
const tileDimensions = Math.ceil(dimensions / globalConfig.tileSize);
this.context.save();
this.context.scale(1 / scale, 1 / scale);
this.context.translate(
startTileX * globalConfig.tileSize - startWorldX,
startTileY * globalConfig.tileSize - startWorldY
);
for (let dx = 0; dx < tileDimensions; ++dx) {
for (let dy = 0; dy < tileDimensions; ++dy) {
const tileX = dx + startTileX;
const tileY = dy + startTileY;
const content = this.root.map.getLayerContentXY(tileX, tileY, "wires");
if (content) {
MapChunkView.drawSingleWiresOverviewTile({
context: this.context,
x: dx * globalConfig.tileSize,
y: dy * globalConfig.tileSize,
entity: content,
tileSizePixels: globalConfig.tileSize,
});
}
}
}
this.context.restore();
this.context.globalCompositeOperation = "destination-in";
this.previewOverlay.draw(this.context, 0, 0, this.previewSize, this.previewSize);
this.context.globalCompositeOperation = "source-over";
return this.canvas;
}
/**
* Renders the preview at the given position
* @param {import("../../../core/draw_utils").DrawParameters} parameters
* @param {Vector} worldPos
* @param {number} scale 1 / zoomLevel
*/
renderPreview(parameters, worldPos, scale) {
if (this.root.currentLayer !== "regular") {
// Only supporting wires right now
return;
}
const canvas = this.prepareCanvasForPreview(worldPos, scale);
parameters.context.globalAlpha = 0.3;
parameters.context.drawImage(
canvas,
worldPos.x - (scale * this.previewSize) / 2,
worldPos.y - (scale * this.previewSize) / 2,
scale * this.previewSize,
scale * this.previewSize
);
parameters.context.globalAlpha = 1;
}
}