1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2024-10-27 20:34:29 +00:00

Fix rendering bug

This commit is contained in:
tobspr 2020-08-28 20:56:02 +02:00
parent 93f9d7ae23
commit cda31732b1
3 changed files with 544 additions and 526 deletions

View File

@ -277,6 +277,11 @@
<key type="filename">sprites/blueprints/underground_belt_entry.png</key> <key type="filename">sprites/blueprints/underground_belt_entry.png</key>
<key type="filename">sprites/blueprints/underground_belt_exit-tier2.png</key> <key type="filename">sprites/blueprints/underground_belt_exit-tier2.png</key>
<key type="filename">sprites/blueprints/underground_belt_exit.png</key> <key type="filename">sprites/blueprints/underground_belt_exit.png</key>
<key type="filename">sprites/blueprints/virtual_processor-analyzer.png</key>
<key type="filename">sprites/blueprints/virtual_processor-rotater.png</key>
<key type="filename">sprites/blueprints/virtual_processor-shapecompare.png</key>
<key type="filename">sprites/blueprints/virtual_processor-unstacker.png</key>
<key type="filename">sprites/blueprints/virtual_processor.png</key>
<key type="filename">sprites/blueprints/wire_tunnel-coating.png</key> <key type="filename">sprites/blueprints/wire_tunnel-coating.png</key>
<key type="filename">sprites/blueprints/wire_tunnel.png</key> <key type="filename">sprites/blueprints/wire_tunnel.png</key>
<key type="filename">sprites/buildings/constant_signal.png</key> <key type="filename">sprites/buildings/constant_signal.png</key>
@ -296,6 +301,11 @@
<key type="filename">sprites/buildings/underground_belt_entry.png</key> <key type="filename">sprites/buildings/underground_belt_entry.png</key>
<key type="filename">sprites/buildings/underground_belt_exit-tier2.png</key> <key type="filename">sprites/buildings/underground_belt_exit-tier2.png</key>
<key type="filename">sprites/buildings/underground_belt_exit.png</key> <key type="filename">sprites/buildings/underground_belt_exit.png</key>
<key type="filename">sprites/buildings/virtual_processor-analyzer.png</key>
<key type="filename">sprites/buildings/virtual_processor-rotater.png</key>
<key type="filename">sprites/buildings/virtual_processor-shapecompare.png</key>
<key type="filename">sprites/buildings/virtual_processor-unstacker.png</key>
<key type="filename">sprites/buildings/virtual_processor.png</key>
<key type="filename">sprites/buildings/wire_tunnel-coating.png</key> <key type="filename">sprites/buildings/wire_tunnel-coating.png</key>
<key type="filename">sprites/buildings/wire_tunnel.png</key> <key type="filename">sprites/buildings/wire_tunnel.png</key>
<key type="filename">sprites/wires/lever_on.png</key> <key type="filename">sprites/wires/lever_on.png</key>

View File

@ -1,274 +1,281 @@
import { globalConfig } from "../core/config"; import { globalConfig } from "../core/config";
import { DrawParameters } from "../core/draw_parameters"; import { DrawParameters } from "../core/draw_parameters";
import { getBuildingDataFromCode } from "./building_codes"; import { getBuildingDataFromCode } from "./building_codes";
import { Entity } from "./entity"; import { Entity } from "./entity";
import { MapChunk } from "./map_chunk"; import { MapChunk } from "./map_chunk";
import { GameRoot } from "./root"; import { GameRoot } from "./root";
import { THEME } from "./theme"; import { THEME } from "./theme";
import { drawSpriteClipped } from "../core/draw_utils"; import { drawSpriteClipped } from "../core/draw_utils";
export const CHUNK_OVERLAY_RES = 3; export const CHUNK_OVERLAY_RES = 3;
export class MapChunkView extends MapChunk { export class MapChunkView extends MapChunk {
/** /**
* *
* @param {GameRoot} root * @param {GameRoot} root
* @param {number} x * @param {number} x
* @param {number} y * @param {number} y
*/ */
constructor(root, x, y) { constructor(root, x, y) {
super(root, x, y); super(root, x, y);
/** /**
* Whenever something changes, we increase this number - so we know we need to redraw * Whenever something changes, we increase this number - so we know we need to redraw
*/ */
this.renderIteration = 0; this.renderIteration = 0;
this.markDirty(); this.markDirty();
} }
/** /**
* Marks this chunk as dirty, rerendering all caches * Marks this chunk as dirty, rerendering all caches
*/ */
markDirty() { markDirty() {
++this.renderIteration; ++this.renderIteration;
this.renderKey = this.x + "/" + this.y + "@" + this.renderIteration; this.renderKey = this.x + "/" + this.y + "@" + this.renderIteration;
} }
/** /**
* Draws the background layer * Draws the background layer
* @param {DrawParameters} parameters * @param {DrawParameters} parameters
*/ */
drawBackgroundLayer(parameters) { drawBackgroundLayer(parameters) {
const systems = this.root.systemMgr.systems; const systems = this.root.systemMgr.systems;
systems.mapResources.drawChunk(parameters, this); systems.mapResources.drawChunk(parameters, this);
systems.beltUnderlays.drawChunk(parameters, this); systems.beltUnderlays.drawChunk(parameters, this);
systems.belt.drawChunk(parameters, this); systems.belt.drawChunk(parameters, this);
} }
/** /**
* Draws the foreground layer * Draws the dynamic foreground layer
* @param {DrawParameters} parameters * @param {DrawParameters} parameters
*/ */
drawForegroundLayer(parameters) { drawForegroundDynamicLayer(parameters) {
const systems = this.root.systemMgr.systems; const systems = this.root.systemMgr.systems;
systems.itemEjector.drawChunk(parameters, this); systems.itemEjector.drawChunk(parameters, this);
systems.itemAcceptor.drawChunk(parameters, this); systems.itemAcceptor.drawChunk(parameters, this);
systems.miner.drawChunk(parameters, this);
systems.miner.drawChunk(parameters, this); }
systems.staticMapEntities.drawChunk(parameters, this); /**
systems.lever.drawChunk(parameters, this); * Draws the static foreground layer
systems.display.drawChunk(parameters, this); * @param {DrawParameters} parameters
systems.storage.drawChunk(parameters, this); */
} drawForegroundStaticLayer(parameters) {
const systems = this.root.systemMgr.systems;
/**
* Overlay systems.staticMapEntities.drawChunk(parameters, this);
* @param {DrawParameters} parameters systems.lever.drawChunk(parameters, this);
*/ systems.display.drawChunk(parameters, this);
drawOverlay(parameters) { systems.storage.drawChunk(parameters, this);
const overlaySize = globalConfig.mapChunkSize * CHUNK_OVERLAY_RES; }
const sprite = this.root.buffers.getForKey({
key: "chunk@" + this.root.currentLayer, /**
subKey: this.renderKey, * Overlay
w: overlaySize, * @param {DrawParameters} parameters
h: overlaySize, */
dpi: 1, drawOverlay(parameters) {
redrawMethod: this.generateOverlayBuffer.bind(this), const overlaySize = globalConfig.mapChunkSize * CHUNK_OVERLAY_RES;
}); const sprite = this.root.buffers.getForKey({
key: "chunk@" + this.root.currentLayer,
const dims = globalConfig.mapChunkWorldSize; subKey: this.renderKey,
w: overlaySize,
// Draw chunk "pixel" art h: overlaySize,
parameters.context.imageSmoothingEnabled = false; dpi: 1,
drawSpriteClipped({ redrawMethod: this.generateOverlayBuffer.bind(this),
parameters, });
sprite,
x: this.x * dims, const dims = globalConfig.mapChunkWorldSize;
y: this.y * dims,
w: dims, // Draw chunk "pixel" art
h: dims, parameters.context.imageSmoothingEnabled = false;
originalW: overlaySize, drawSpriteClipped({
originalH: overlaySize, parameters,
}); sprite,
x: this.x * dims,
parameters.context.imageSmoothingEnabled = true; y: this.y * dims,
w: dims,
// Draw patch items h: dims,
if (this.root.currentLayer === "regular") { originalW: overlaySize,
for (let i = 0; i < this.patches.length; ++i) { originalH: overlaySize,
const patch = this.patches[i]; });
const destX = this.x * dims + patch.pos.x * globalConfig.tileSize; parameters.context.imageSmoothingEnabled = true;
const destY = this.y * dims + patch.pos.y * globalConfig.tileSize;
const diameter = Math.min(80, 30 / parameters.zoomLevel); // Draw patch items
if (this.root.currentLayer === "regular") {
patch.item.drawItemCenteredClipped(destX, destY, parameters, diameter); for (let i = 0; i < this.patches.length; ++i) {
} const patch = this.patches[i];
}
} const destX = this.x * dims + patch.pos.x * globalConfig.tileSize;
const destY = this.y * dims + patch.pos.y * globalConfig.tileSize;
/** const diameter = Math.min(80, 30 / parameters.zoomLevel);
*
* @param {HTMLCanvasElement} canvas patch.item.drawItemCenteredClipped(destX, destY, parameters, diameter);
* @param {CanvasRenderingContext2D} context }
* @param {number} w }
* @param {number} h }
* @param {number} dpi
*/ /**
generateOverlayBuffer(canvas, context, w, h, dpi) { *
context.fillStyle = * @param {HTMLCanvasElement} canvas
this.containedEntities.length > 0 * @param {CanvasRenderingContext2D} context
? THEME.map.chunkOverview.filled * @param {number} w
: THEME.map.chunkOverview.empty; * @param {number} h
context.fillRect(0, 0, w, h); * @param {number} dpi
*/
for (let x = 0; x < globalConfig.mapChunkSize; ++x) { generateOverlayBuffer(canvas, context, w, h, dpi) {
const lowerArray = this.lowerLayer[x]; context.fillStyle =
const upperArray = this.contents[x]; this.containedEntities.length > 0
for (let y = 0; y < globalConfig.mapChunkSize; ++y) { ? THEME.map.chunkOverview.filled
const upperContent = upperArray[y]; : THEME.map.chunkOverview.empty;
if (upperContent) { context.fillRect(0, 0, w, h);
const staticComp = upperContent.components.StaticMapEntity;
const data = getBuildingDataFromCode(staticComp.code); for (let x = 0; x < globalConfig.mapChunkSize; ++x) {
const metaBuilding = data.metaInstance; const lowerArray = this.lowerLayer[x];
const upperArray = this.contents[x];
const overlayMatrix = metaBuilding.getSpecialOverlayRenderMatrix( for (let y = 0; y < globalConfig.mapChunkSize; ++y) {
staticComp.rotation, const upperContent = upperArray[y];
data.rotationVariant, if (upperContent) {
data.variant, const staticComp = upperContent.components.StaticMapEntity;
upperContent const data = getBuildingDataFromCode(staticComp.code);
); const metaBuilding = data.metaInstance;
if (overlayMatrix) { const overlayMatrix = metaBuilding.getSpecialOverlayRenderMatrix(
// Draw lower content first since it "shines" through staticComp.rotation,
const lowerContent = lowerArray[y]; data.rotationVariant,
if (lowerContent) { data.variant,
context.fillStyle = lowerContent.getBackgroundColorAsResource(); upperContent
context.fillRect( );
x * CHUNK_OVERLAY_RES,
y * CHUNK_OVERLAY_RES, if (overlayMatrix) {
CHUNK_OVERLAY_RES, // Draw lower content first since it "shines" through
CHUNK_OVERLAY_RES const lowerContent = lowerArray[y];
); if (lowerContent) {
} context.fillStyle = lowerContent.getBackgroundColorAsResource();
context.fillRect(
context.fillStyle = metaBuilding.getSilhouetteColor(); x * CHUNK_OVERLAY_RES,
for (let dx = 0; dx < 3; ++dx) { y * CHUNK_OVERLAY_RES,
for (let dy = 0; dy < 3; ++dy) { CHUNK_OVERLAY_RES,
const isFilled = overlayMatrix[dx + dy * 3]; CHUNK_OVERLAY_RES
if (isFilled) { );
context.fillRect( }
x * CHUNK_OVERLAY_RES + dx,
y * CHUNK_OVERLAY_RES + dy, context.fillStyle = metaBuilding.getSilhouetteColor();
1, for (let dx = 0; dx < 3; ++dx) {
1 for (let dy = 0; dy < 3; ++dy) {
); const isFilled = overlayMatrix[dx + dy * 3];
} if (isFilled) {
} context.fillRect(
} x * CHUNK_OVERLAY_RES + dx,
y * CHUNK_OVERLAY_RES + dy,
continue; 1,
} else { 1
context.fillStyle = metaBuilding.getSilhouetteColor(); );
context.fillRect( }
x * CHUNK_OVERLAY_RES, }
y * CHUNK_OVERLAY_RES, }
CHUNK_OVERLAY_RES,
CHUNK_OVERLAY_RES continue;
); } else {
context.fillStyle = metaBuilding.getSilhouetteColor();
continue; context.fillRect(
} x * CHUNK_OVERLAY_RES,
} y * CHUNK_OVERLAY_RES,
CHUNK_OVERLAY_RES,
const lowerContent = lowerArray[y]; CHUNK_OVERLAY_RES
if (lowerContent) { );
context.fillStyle = lowerContent.getBackgroundColorAsResource();
context.fillRect( continue;
x * CHUNK_OVERLAY_RES, }
y * CHUNK_OVERLAY_RES, }
CHUNK_OVERLAY_RES,
CHUNK_OVERLAY_RES const lowerContent = lowerArray[y];
); if (lowerContent) {
} context.fillStyle = lowerContent.getBackgroundColorAsResource();
} context.fillRect(
} x * CHUNK_OVERLAY_RES,
y * CHUNK_OVERLAY_RES,
if (this.root.currentLayer === "wires") { CHUNK_OVERLAY_RES,
// Draw wires overlay CHUNK_OVERLAY_RES
);
context.fillStyle = THEME.map.wires.overlayColor; }
context.fillRect(0, 0, w, h); }
}
for (let x = 0; x < globalConfig.mapChunkSize; ++x) {
const wiresArray = this.wireContents[x]; if (this.root.currentLayer === "wires") {
for (let y = 0; y < globalConfig.mapChunkSize; ++y) { // Draw wires overlay
const content = wiresArray[y];
if (!content) { context.fillStyle = THEME.map.wires.overlayColor;
continue; context.fillRect(0, 0, w, h);
}
MapChunkView.drawSingleWiresOverviewTile({ for (let x = 0; x < globalConfig.mapChunkSize; ++x) {
context, const wiresArray = this.wireContents[x];
x: x * CHUNK_OVERLAY_RES, for (let y = 0; y < globalConfig.mapChunkSize; ++y) {
y: y * CHUNK_OVERLAY_RES, const content = wiresArray[y];
entity: content, if (!content) {
tileSizePixels: CHUNK_OVERLAY_RES, continue;
}); }
} MapChunkView.drawSingleWiresOverviewTile({
} context,
} x: x * CHUNK_OVERLAY_RES,
} y: y * CHUNK_OVERLAY_RES,
entity: content,
/** tileSizePixels: CHUNK_OVERLAY_RES,
* @param {object} param0 });
* @param {CanvasRenderingContext2D} param0.context }
* @param {number} param0.x }
* @param {number} param0.y }
* @param {Entity} param0.entity }
* @param {number} param0.tileSizePixels
* @param {string=} param0.overrideColor Optionally override the color to be rendered /**
*/ * @param {object} param0
static drawSingleWiresOverviewTile({ context, x, y, entity, tileSizePixels, overrideColor = null }) { * @param {CanvasRenderingContext2D} param0.context
const staticComp = entity.components.StaticMapEntity; * @param {number} param0.x
const data = getBuildingDataFromCode(staticComp.code); * @param {number} param0.y
const metaBuilding = data.metaInstance; * @param {Entity} param0.entity
const overlayMatrix = metaBuilding.getSpecialOverlayRenderMatrix( * @param {number} param0.tileSizePixels
staticComp.rotation, * @param {string=} param0.overrideColor Optionally override the color to be rendered
data.rotationVariant, */
data.variant, static drawSingleWiresOverviewTile({ context, x, y, entity, tileSizePixels, overrideColor = null }) {
entity const staticComp = entity.components.StaticMapEntity;
); const data = getBuildingDataFromCode(staticComp.code);
context.fillStyle = overrideColor || metaBuilding.getSilhouetteColor(); const metaBuilding = data.metaInstance;
if (overlayMatrix) { const overlayMatrix = metaBuilding.getSpecialOverlayRenderMatrix(
for (let dx = 0; dx < 3; ++dx) { staticComp.rotation,
for (let dy = 0; dy < 3; ++dy) { data.rotationVariant,
const isFilled = overlayMatrix[dx + dy * 3]; data.variant,
if (isFilled) { entity
context.fillRect( );
x + (dx * tileSizePixels) / CHUNK_OVERLAY_RES, context.fillStyle = overrideColor || metaBuilding.getSilhouetteColor();
y + (dy * tileSizePixels) / CHUNK_OVERLAY_RES, if (overlayMatrix) {
tileSizePixels / CHUNK_OVERLAY_RES, for (let dx = 0; dx < 3; ++dx) {
tileSizePixels / CHUNK_OVERLAY_RES for (let dy = 0; dy < 3; ++dy) {
); const isFilled = overlayMatrix[dx + dy * 3];
} if (isFilled) {
} context.fillRect(
} x + (dx * tileSizePixels) / CHUNK_OVERLAY_RES,
} else { y + (dy * tileSizePixels) / CHUNK_OVERLAY_RES,
context.fillRect(x, y, tileSizePixels, tileSizePixels); tileSizePixels / CHUNK_OVERLAY_RES,
} tileSizePixels / CHUNK_OVERLAY_RES
} );
}
/** }
* Draws the wires layer }
* @param {DrawParameters} parameters } else {
*/ context.fillRect(x, y, tileSizePixels, tileSizePixels);
drawWiresForegroundLayer(parameters) { }
const systems = this.root.systemMgr.systems; }
systems.wire.drawChunk(parameters, this);
systems.staticMapEntities.drawWiresChunk(parameters, this); /**
systems.wiredPins.drawChunk(parameters, this); * Draws the wires layer
} * @param {DrawParameters} parameters
} */
drawWiresForegroundLayer(parameters) {
const systems = this.root.systemMgr.systems;
systems.wire.drawChunk(parameters, this);
systems.staticMapEntities.drawWiresChunk(parameters, this);
systems.wiredPins.drawChunk(parameters, this);
}
}

View File

@ -1,252 +1,253 @@
import { globalConfig } from "../core/config"; import { globalConfig } from "../core/config";
import { DrawParameters } from "../core/draw_parameters"; import { DrawParameters } from "../core/draw_parameters";
import { BaseMap } from "./map"; import { BaseMap } from "./map";
import { freeCanvas, makeOffscreenBuffer } from "../core/buffer_utils"; import { freeCanvas, makeOffscreenBuffer } from "../core/buffer_utils";
import { Entity } from "./entity"; import { Entity } from "./entity";
import { THEME } from "./theme"; import { THEME } from "./theme";
import { MapChunkView } from "./map_chunk_view"; import { MapChunkView } from "./map_chunk_view";
/** /**
* This is the view of the map, it extends the map which is the raw model and allows * This is the view of the map, it extends the map which is the raw model and allows
* to draw it * to draw it
*/ */
export class MapView extends BaseMap { export class MapView extends BaseMap {
constructor(root) { constructor(root) {
super(root); super(root);
/** /**
* DPI of the background cache images, required in some places * DPI of the background cache images, required in some places
*/ */
this.backgroundCacheDPI = 2; this.backgroundCacheDPI = 2;
/** /**
* The cached background sprite, containing the flat background * The cached background sprite, containing the flat background
* @type {HTMLCanvasElement} */ * @type {HTMLCanvasElement} */
this.cachedBackgroundCanvas = null; this.cachedBackgroundCanvas = null;
/** @type {CanvasRenderingContext2D} */ /** @type {CanvasRenderingContext2D} */
this.cachedBackgroundContext = null; this.cachedBackgroundContext = null;
/** /**
* Cached pattern of the stripes background * Cached pattern of the stripes background
* @type {CanvasPattern} */ * @type {CanvasPattern} */
this.cachedBackgroundPattern = null; this.cachedBackgroundPattern = null;
this.internalInitializeCachedBackgroundCanvases(); this.internalInitializeCachedBackgroundCanvases();
this.root.signals.aboutToDestruct.add(this.cleanup, this); this.root.signals.aboutToDestruct.add(this.cleanup, this);
this.root.signals.entityAdded.add(this.onEntityChanged, this); this.root.signals.entityAdded.add(this.onEntityChanged, this);
this.root.signals.entityDestroyed.add(this.onEntityChanged, this); this.root.signals.entityDestroyed.add(this.onEntityChanged, this);
this.root.signals.entityChanged.add(this.onEntityChanged, this); this.root.signals.entityChanged.add(this.onEntityChanged, this);
} }
cleanup() { cleanup() {
freeCanvas(this.cachedBackgroundCanvas); freeCanvas(this.cachedBackgroundCanvas);
this.cachedBackgroundCanvas = null; this.cachedBackgroundCanvas = null;
this.cachedBackgroundPattern = null; this.cachedBackgroundPattern = null;
} }
/** /**
* Called when an entity was added, removed or changed * Called when an entity was added, removed or changed
* @param {Entity} entity * @param {Entity} entity
*/ */
onEntityChanged(entity) { onEntityChanged(entity) {
const staticComp = entity.components.StaticMapEntity; const staticComp = entity.components.StaticMapEntity;
if (staticComp) { if (staticComp) {
const rect = staticComp.getTileSpaceBounds(); const rect = staticComp.getTileSpaceBounds();
for (let x = rect.x; x <= rect.right(); ++x) { for (let x = rect.x; x <= rect.right(); ++x) {
for (let y = rect.y; y <= rect.bottom(); ++y) { for (let y = rect.y; y <= rect.bottom(); ++y) {
this.root.map.getOrCreateChunkAtTile(x, y).markDirty(); this.root.map.getOrCreateChunkAtTile(x, y).markDirty();
} }
} }
} }
} }
/** /**
* Draws all static entities like buildings etc. * Draws all static entities like buildings etc.
* @param {DrawParameters} drawParameters * @param {DrawParameters} drawParameters
*/ */
drawStaticEntityDebugOverlays(drawParameters) { drawStaticEntityDebugOverlays(drawParameters) {
const cullRange = drawParameters.visibleRect.toTileCullRectangle(); const cullRange = drawParameters.visibleRect.toTileCullRectangle();
const top = cullRange.top(); const top = cullRange.top();
const right = cullRange.right(); const right = cullRange.right();
const bottom = cullRange.bottom(); const bottom = cullRange.bottom();
const left = cullRange.left(); const left = cullRange.left();
const border = 1; const border = 1;
const minY = top - border; const minY = top - border;
const maxY = bottom + border; const maxY = bottom + border;
const minX = left - border; const minX = left - border;
const maxX = right + border - 1; const maxX = right + border - 1;
// Render y from top down for proper blending // Render y from top down for proper blending
for (let y = minY; y <= maxY; ++y) { for (let y = minY; y <= maxY; ++y) {
for (let x = minX; x <= maxX; ++x) { for (let x = minX; x <= maxX; ++x) {
// const content = this.tiles[x][y]; // const content = this.tiles[x][y];
const chunk = this.getChunkAtTileOrNull(x, y); const chunk = this.getChunkAtTileOrNull(x, y);
if (!chunk) { if (!chunk) {
continue; continue;
} }
const content = chunk.getTileContentFromWorldCoords(x, y); const content = chunk.getTileContentFromWorldCoords(x, y);
if (content) { if (content) {
let isBorder = x <= left - 1 || x >= right + 1 || y <= top - 1 || y >= bottom + 1; let isBorder = x <= left - 1 || x >= right + 1 || y <= top - 1 || y >= bottom + 1;
if (!isBorder) { if (!isBorder) {
content.drawDebugOverlays(drawParameters); content.drawDebugOverlays(drawParameters);
} }
} }
} }
} }
} }
/** /**
* Initializes all canvases used for background rendering * Initializes all canvases used for background rendering
*/ */
internalInitializeCachedBackgroundCanvases() { internalInitializeCachedBackgroundCanvases() {
// Background canvas // Background canvas
const dims = globalConfig.tileSize; const dims = globalConfig.tileSize;
const dpi = this.backgroundCacheDPI; const dpi = this.backgroundCacheDPI;
const [canvas, context] = makeOffscreenBuffer(dims * dpi, dims * dpi, { const [canvas, context] = makeOffscreenBuffer(dims * dpi, dims * dpi, {
smooth: false, smooth: false,
label: "map-cached-bg", label: "map-cached-bg",
}); });
context.scale(dpi, dpi); context.scale(dpi, dpi);
context.fillStyle = THEME.map.background; context.fillStyle = THEME.map.background;
context.fillRect(0, 0, dims, dims); context.fillRect(0, 0, dims, dims);
const borderWidth = THEME.map.gridLineWidth; const borderWidth = THEME.map.gridLineWidth;
context.fillStyle = THEME.map.grid; context.fillStyle = THEME.map.grid;
context.fillRect(0, 0, dims, borderWidth); context.fillRect(0, 0, dims, borderWidth);
context.fillRect(0, borderWidth, borderWidth, dims); context.fillRect(0, borderWidth, borderWidth, dims);
context.fillRect(dims - borderWidth, borderWidth, borderWidth, dims - 2 * borderWidth); context.fillRect(dims - borderWidth, borderWidth, borderWidth, dims - 2 * borderWidth);
context.fillRect(borderWidth, dims - borderWidth, dims, borderWidth); context.fillRect(borderWidth, dims - borderWidth, dims, borderWidth);
this.cachedBackgroundCanvas = canvas; this.cachedBackgroundCanvas = canvas;
this.cachedBackgroundContext = context; this.cachedBackgroundContext = context;
} }
/** /**
* Draws the maps foreground * Draws the maps foreground
* @param {DrawParameters} parameters * @param {DrawParameters} parameters
*/ */
drawForeground(parameters) { drawForeground(parameters) {
this.drawVisibleChunks(parameters, MapChunkView.prototype.drawForegroundLayer); this.drawVisibleChunks(parameters, MapChunkView.prototype.drawForegroundDynamicLayer);
} this.drawVisibleChunks(parameters, MapChunkView.prototype.drawForegroundStaticLayer);
}
/**
* Calls a given method on all given chunks /**
* @param {DrawParameters} parameters * Calls a given method on all given chunks
* @param {function} method * @param {DrawParameters} parameters
*/ * @param {function} method
drawVisibleChunks(parameters, method) { */
const cullRange = parameters.visibleRect.allScaled(1 / globalConfig.tileSize); drawVisibleChunks(parameters, method) {
const top = cullRange.top(); const cullRange = parameters.visibleRect.allScaled(1 / globalConfig.tileSize);
const right = cullRange.right(); const top = cullRange.top();
const bottom = cullRange.bottom(); const right = cullRange.right();
const left = cullRange.left(); const bottom = cullRange.bottom();
const left = cullRange.left();
const border = 0;
const minY = top - border; const border = 0;
const maxY = bottom + border; const minY = top - border;
const minX = left - border; const maxY = bottom + border;
const maxX = right + border; const minX = left - border;
const maxX = right + border;
const chunkStartX = Math.floor(minX / globalConfig.mapChunkSize);
const chunkStartY = Math.floor(minY / globalConfig.mapChunkSize); const chunkStartX = Math.floor(minX / globalConfig.mapChunkSize);
const chunkStartY = Math.floor(minY / globalConfig.mapChunkSize);
const chunkEndX = Math.floor(maxX / globalConfig.mapChunkSize);
const chunkEndY = Math.floor(maxY / globalConfig.mapChunkSize); const chunkEndX = Math.floor(maxX / globalConfig.mapChunkSize);
const chunkEndY = Math.floor(maxY / globalConfig.mapChunkSize);
// Render y from top down for proper blending
for (let chunkX = chunkStartX; chunkX <= chunkEndX; ++chunkX) { // Render y from top down for proper blending
for (let chunkY = chunkStartY; chunkY <= chunkEndY; ++chunkY) { for (let chunkX = chunkStartX; chunkX <= chunkEndX; ++chunkX) {
const chunk = this.root.map.getChunk(chunkX, chunkY, true); for (let chunkY = chunkStartY; chunkY <= chunkEndY; ++chunkY) {
method.call(chunk, parameters); const chunk = this.root.map.getChunk(chunkX, chunkY, true);
} method.call(chunk, parameters);
} }
} }
}
/**
* Draws the wires foreground /**
* @param {DrawParameters} parameters * Draws the wires foreground
*/ * @param {DrawParameters} parameters
drawWiresForegroundLayer(parameters) { */
this.drawVisibleChunks(parameters, MapChunkView.prototype.drawWiresForegroundLayer); drawWiresForegroundLayer(parameters) {
} this.drawVisibleChunks(parameters, MapChunkView.prototype.drawWiresForegroundLayer);
}
/**
* Draws the map overlay /**
* @param {DrawParameters} parameters * Draws the map overlay
*/ * @param {DrawParameters} parameters
drawOverlay(parameters) { */
this.drawVisibleChunks(parameters, MapChunkView.prototype.drawOverlay); drawOverlay(parameters) {
} this.drawVisibleChunks(parameters, MapChunkView.prototype.drawOverlay);
}
/**
* Draws the map background /**
* @param {DrawParameters} parameters * Draws the map background
*/ * @param {DrawParameters} parameters
drawBackground(parameters) { */
if (!this.cachedBackgroundPattern) { drawBackground(parameters) {
this.cachedBackgroundPattern = parameters.context.createPattern( if (!this.cachedBackgroundPattern) {
this.cachedBackgroundCanvas, this.cachedBackgroundPattern = parameters.context.createPattern(
"repeat" this.cachedBackgroundCanvas,
); "repeat"
} );
}
if (!this.root.app.settings.getAllSettings().disableTileGrid) {
const dpi = this.backgroundCacheDPI; if (!this.root.app.settings.getAllSettings().disableTileGrid) {
parameters.context.scale(1 / dpi, 1 / dpi); const dpi = this.backgroundCacheDPI;
parameters.context.scale(1 / dpi, 1 / dpi);
parameters.context.fillStyle = this.cachedBackgroundPattern;
parameters.context.fillRect( parameters.context.fillStyle = this.cachedBackgroundPattern;
parameters.visibleRect.x * dpi, parameters.context.fillRect(
parameters.visibleRect.y * dpi, parameters.visibleRect.x * dpi,
parameters.visibleRect.w * dpi, parameters.visibleRect.y * dpi,
parameters.visibleRect.h * dpi parameters.visibleRect.w * dpi,
); parameters.visibleRect.h * dpi
parameters.context.scale(dpi, dpi); );
} parameters.context.scale(dpi, dpi);
}
this.drawVisibleChunks(parameters, MapChunkView.prototype.drawBackgroundLayer);
this.drawVisibleChunks(parameters, MapChunkView.prototype.drawBackgroundLayer);
if (G_IS_DEV && globalConfig.debug.showChunkBorders) {
const cullRange = parameters.visibleRect.toTileCullRectangle(); if (G_IS_DEV && globalConfig.debug.showChunkBorders) {
const top = cullRange.top(); const cullRange = parameters.visibleRect.toTileCullRectangle();
const right = cullRange.right(); const top = cullRange.top();
const bottom = cullRange.bottom(); const right = cullRange.right();
const left = cullRange.left(); const bottom = cullRange.bottom();
const left = cullRange.left();
const border = 1;
const minY = top - border; const border = 1;
const maxY = bottom + border; const minY = top - border;
const minX = left - border; const maxY = bottom + border;
const maxX = right + border - 1; const minX = left - border;
const maxX = right + border - 1;
const chunkStartX = Math.floor(minX / globalConfig.mapChunkSize);
const chunkStartY = Math.floor(minY / globalConfig.mapChunkSize); const chunkStartX = Math.floor(minX / globalConfig.mapChunkSize);
const chunkStartY = Math.floor(minY / globalConfig.mapChunkSize);
const chunkEndX = Math.ceil(maxX / globalConfig.mapChunkSize);
const chunkEndY = Math.ceil(maxY / globalConfig.mapChunkSize); const chunkEndX = Math.ceil(maxX / globalConfig.mapChunkSize);
const chunkEndY = Math.ceil(maxY / globalConfig.mapChunkSize);
for (let chunkX = chunkStartX; chunkX <= chunkEndX; ++chunkX) {
for (let chunkY = chunkStartY; chunkY <= chunkEndY; ++chunkY) { for (let chunkX = chunkStartX; chunkX <= chunkEndX; ++chunkX) {
parameters.context.fillStyle = "#ffaaaa"; for (let chunkY = chunkStartY; chunkY <= chunkEndY; ++chunkY) {
parameters.context.fillRect( parameters.context.fillStyle = "#ffaaaa";
chunkX * globalConfig.mapChunkWorldSize, parameters.context.fillRect(
chunkY * globalConfig.mapChunkWorldSize, chunkX * globalConfig.mapChunkWorldSize,
globalConfig.mapChunkWorldSize, chunkY * globalConfig.mapChunkWorldSize,
3 globalConfig.mapChunkWorldSize,
); 3
parameters.context.fillRect( );
chunkX * globalConfig.mapChunkWorldSize, parameters.context.fillRect(
chunkY * globalConfig.mapChunkWorldSize, chunkX * globalConfig.mapChunkWorldSize,
3, chunkY * globalConfig.mapChunkWorldSize,
globalConfig.mapChunkWorldSize 3,
); globalConfig.mapChunkWorldSize
} );
} }
} }
} }
} }
}