169 lines
6.5 KiB
TypeScript
169 lines
6.5 KiB
TypeScript
|
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||
|
|
// @ts-nocheck
|
||
|
|
|
||
|
|
import { BlurFilter, Sprite, Texture } from "pixi.js";
|
||
|
|
import { getWorldBorderThickness, parseHexColor } from "./pixiSurfaceHelpers";
|
||
|
|
|
||
|
|
function createBorderSprite(x, y, width, height, tint, alpha) {
|
||
|
|
const border = new Sprite(Texture.WHITE);
|
||
|
|
border.x = x;
|
||
|
|
border.y = y;
|
||
|
|
border.width = width;
|
||
|
|
border.height = height;
|
||
|
|
border.tint = tint;
|
||
|
|
border.alpha = alpha;
|
||
|
|
return border;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function rebuildHeightOverlay(state, scope, helpers) {
|
||
|
|
if (!helpers.isReady() || !state.heightOverlayRoot) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const overlayMode = scope.isEditingHeightLayer && scope.isEditingHeightLayer() ? "height" : "";
|
||
|
|
const activeEntry = scope.getActiveHeightLayer ? scope.getActiveHeightLayer() : null;
|
||
|
|
const activeId = String(activeEntry?.id || "").trim();
|
||
|
|
if (
|
||
|
|
!state.dirty
|
||
|
|
&& state.lastHeightLayersRef === scope.heightLayers
|
||
|
|
&& state.lastHeightOverlayMode === overlayMode
|
||
|
|
&& state.lastHeightActiveId === activeId
|
||
|
|
&& state.lastHeightTileSize === scope.tileSize
|
||
|
|
) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
state.heightPatchEntries.forEach((entry) => {
|
||
|
|
helpers.destroyHeightPatchEntry(entry);
|
||
|
|
});
|
||
|
|
state.heightPatchEntries.clear();
|
||
|
|
state.heightOverlayRoot.removeChildren();
|
||
|
|
state.lastHeightLayersRef = scope.heightLayers;
|
||
|
|
state.lastHeightOverlayMode = overlayMode;
|
||
|
|
state.lastHeightActiveId = activeId;
|
||
|
|
state.lastHeightTileSize = scope.tileSize;
|
||
|
|
|
||
|
|
if (overlayMode !== "height" || !activeEntry) {
|
||
|
|
state.heightOverlayRoot.visible = false;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
state.heightOverlayRoot.visible = true;
|
||
|
|
const activeZ = Math.max(1, Number(activeEntry.z) || 1);
|
||
|
|
const visibleEntries = (Array.isArray(scope.heightLayers) ? scope.heightLayers : [])
|
||
|
|
.filter((entry) => Math.max(1, Number(entry?.z) || 1) === activeZ);
|
||
|
|
const borderThickness = getWorldBorderThickness(scope.tileSize);
|
||
|
|
visibleEntries.forEach((entry) => {
|
||
|
|
const entryId = String(entry?.id || "").trim();
|
||
|
|
if (!entryId) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const isActive = entryId === activeId;
|
||
|
|
const patchContainer = new helpers.Container();
|
||
|
|
patchContainer.label = `height_${entryId}`;
|
||
|
|
patchContainer.x = Math.max(0, Number(entry?.x) || 0);
|
||
|
|
patchContainer.y = Math.max(0, Number(entry?.y) || 0);
|
||
|
|
patchContainer.alpha = isActive ? 0.92 : 0.56;
|
||
|
|
patchContainer.roundPixels = true;
|
||
|
|
state.heightOverlayRoot.addChild(patchContainer);
|
||
|
|
const rows = Array.isArray(entry?.rows) ? entry.rows : [];
|
||
|
|
let patchWidth = 0;
|
||
|
|
rows.forEach((rawRow, localY) => {
|
||
|
|
const row = String(rawRow || "");
|
||
|
|
patchWidth = Math.max(patchWidth, row.length);
|
||
|
|
for (let localX = 0; localX < row.length; localX += 1) {
|
||
|
|
const symbol = String(row.charAt(localX) || " ").charAt(0) || " ";
|
||
|
|
if (symbol === " " || symbol === ".") {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
const sprite = new Sprite(helpers.getTileTexture(symbol));
|
||
|
|
sprite.x = localX;
|
||
|
|
sprite.y = localY;
|
||
|
|
sprite.width = 1;
|
||
|
|
sprite.height = 1;
|
||
|
|
sprite.roundPixels = true;
|
||
|
|
patchContainer.addChild(sprite);
|
||
|
|
if (isActive) {
|
||
|
|
const shade = new Sprite(Texture.WHITE);
|
||
|
|
shade.x = localX;
|
||
|
|
shade.y = localY;
|
||
|
|
shade.width = 1;
|
||
|
|
shade.height = 1;
|
||
|
|
shade.tint = parseHexColor("#9198A8", 0x9198A8);
|
||
|
|
shade.alpha = 0.28;
|
||
|
|
shade.roundPixels = true;
|
||
|
|
patchContainer.addChild(shade);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
if (patchWidth > 0 && rows.length > 0) {
|
||
|
|
const drawW = patchWidth;
|
||
|
|
const drawH = rows.length;
|
||
|
|
const tint = isActive ? parseHexColor("#FFEB8C", 0xFFEB8C) : parseHexColor("#6EA0EB", 0x6EA0EB);
|
||
|
|
const alpha = isActive ? 0.92 : 0.55;
|
||
|
|
patchContainer.addChild(createBorderSprite(0, 0, drawW, borderThickness, tint, alpha));
|
||
|
|
patchContainer.addChild(createBorderSprite(0, drawH - borderThickness, drawW, borderThickness, tint, alpha));
|
||
|
|
patchContainer.addChild(createBorderSprite(0, 0, borderThickness, drawH, tint, alpha));
|
||
|
|
patchContainer.addChild(createBorderSprite(drawW - borderThickness, 0, borderThickness, drawH, tint, alpha));
|
||
|
|
}
|
||
|
|
state.heightPatchEntries.set(entryId, {
|
||
|
|
id: entryId,
|
||
|
|
container: patchContainer,
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export function resetSceneRoots(state, scope) {
|
||
|
|
if (!state.backgroundSprite || !state.baseWorldRoot) {
|
||
|
|
state.backgroundSprite = new Sprite(Texture.WHITE);
|
||
|
|
state.backgroundSprite.zIndex = -1;
|
||
|
|
state.backgroundSprite.roundPixels = true;
|
||
|
|
}
|
||
|
|
state.backgroundSprite.tint = parseHexColor(scope.normalizeMapBackgroundColor(scope.backgroundColor));
|
||
|
|
state.backgroundSprite.width = Math.max(1, Number(scope.width) || 1);
|
||
|
|
state.backgroundSprite.height = Math.max(1, Number(scope.height) || 1);
|
||
|
|
if (state.backgroundSprite.parent !== state.baseWorldRoot) {
|
||
|
|
state.baseWorldRoot.addChildAt(state.backgroundSprite, 0);
|
||
|
|
}
|
||
|
|
if (state.heightOverlayRoot?.parent !== state.worldContainer) {
|
||
|
|
state.worldContainer.addChild(state.heightOverlayRoot);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export function syncHeightFocusEffect(state, scope) {
|
||
|
|
if (!state.baseWorldRoot) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const activeHeightLayer = scope.getActiveHeightLayer ? scope.getActiveHeightLayer() : null;
|
||
|
|
const activeHeightZ = Math.max(0, Number(activeHeightLayer?.z) || 0);
|
||
|
|
const isHeightModeActive = !!(scope.isEditingHeightLayer && scope.isEditingHeightLayer()) && activeHeightZ > 0;
|
||
|
|
const blurStep = Math.max(
|
||
|
|
0,
|
||
|
|
Math.min(
|
||
|
|
1,
|
||
|
|
Number(scope.getEffectiveHeightBlurStep?.() ?? scope.heightBlurStep ?? scope.heightDetailStep) || 0.1,
|
||
|
|
),
|
||
|
|
);
|
||
|
|
const tileReferenceSize = Math.max(8, Number(scope.baseTileSize) || Number(scope.tileSize) || 32);
|
||
|
|
const nextBlurStrength = isHeightModeActive
|
||
|
|
? Math.min(8, activeHeightZ * blurStep * (tileReferenceSize / 4))
|
||
|
|
: 0;
|
||
|
|
if (!state.heightFocusBlurFilter) {
|
||
|
|
state.heightFocusBlurFilter = new BlurFilter({ strength: 0, quality: 2, kernelSize: 5 });
|
||
|
|
state.heightFocusBlurFilter.repeatEdgePixels = true;
|
||
|
|
}
|
||
|
|
if (isHeightModeActive) {
|
||
|
|
if (!state.heightFocusCacheEnabled || Math.abs(nextBlurStrength - state.heightFocusBlurStrength) > 0.001) {
|
||
|
|
state.heightFocusBlurFilter.strength = nextBlurStrength;
|
||
|
|
state.baseWorldRoot.filters = [state.heightFocusBlurFilter];
|
||
|
|
state.heightFocusCacheEnabled = true;
|
||
|
|
state.heightFocusBlurStrength = nextBlurStrength;
|
||
|
|
}
|
||
|
|
} else if (state.heightFocusCacheEnabled) {
|
||
|
|
state.baseWorldRoot.filters = [];
|
||
|
|
state.heightFocusCacheEnabled = false;
|
||
|
|
state.heightFocusBlurStrength = 0;
|
||
|
|
}
|
||
|
|
state.baseWorldRoot.alpha = isHeightModeActive
|
||
|
|
? Math.max(0.92, 1 - (activeHeightZ * 0.015))
|
||
|
|
: 1;
|
||
|
|
}
|