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:
parent
93f9d7ae23
commit
cda31732b1
@ -277,6 +277,11 @@
|
||||
<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.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.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_exit-tier2.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.png</key>
|
||||
<key type="filename">sprites/wires/lever_on.png</key>
|
||||
|
@ -1,274 +1,281 @@
|
||||
import { globalConfig } from "../core/config";
|
||||
import { DrawParameters } from "../core/draw_parameters";
|
||||
import { getBuildingDataFromCode } from "./building_codes";
|
||||
import { Entity } from "./entity";
|
||||
import { MapChunk } from "./map_chunk";
|
||||
import { GameRoot } from "./root";
|
||||
import { THEME } from "./theme";
|
||||
import { drawSpriteClipped } from "../core/draw_utils";
|
||||
|
||||
export const CHUNK_OVERLAY_RES = 3;
|
||||
|
||||
export class MapChunkView extends MapChunk {
|
||||
/**
|
||||
*
|
||||
* @param {GameRoot} root
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
*/
|
||||
constructor(root, x, y) {
|
||||
super(root, x, y);
|
||||
|
||||
/**
|
||||
* Whenever something changes, we increase this number - so we know we need to redraw
|
||||
*/
|
||||
this.renderIteration = 0;
|
||||
|
||||
this.markDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this chunk as dirty, rerendering all caches
|
||||
*/
|
||||
markDirty() {
|
||||
++this.renderIteration;
|
||||
this.renderKey = this.x + "/" + this.y + "@" + this.renderIteration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the background layer
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawBackgroundLayer(parameters) {
|
||||
const systems = this.root.systemMgr.systems;
|
||||
systems.mapResources.drawChunk(parameters, this);
|
||||
systems.beltUnderlays.drawChunk(parameters, this);
|
||||
systems.belt.drawChunk(parameters, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the foreground layer
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawForegroundLayer(parameters) {
|
||||
const systems = this.root.systemMgr.systems;
|
||||
|
||||
systems.itemEjector.drawChunk(parameters, this);
|
||||
systems.itemAcceptor.drawChunk(parameters, this);
|
||||
|
||||
systems.miner.drawChunk(parameters, this);
|
||||
|
||||
systems.staticMapEntities.drawChunk(parameters, this);
|
||||
systems.lever.drawChunk(parameters, this);
|
||||
systems.display.drawChunk(parameters, this);
|
||||
systems.storage.drawChunk(parameters, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overlay
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawOverlay(parameters) {
|
||||
const overlaySize = globalConfig.mapChunkSize * CHUNK_OVERLAY_RES;
|
||||
const sprite = this.root.buffers.getForKey({
|
||||
key: "chunk@" + this.root.currentLayer,
|
||||
subKey: this.renderKey,
|
||||
w: overlaySize,
|
||||
h: overlaySize,
|
||||
dpi: 1,
|
||||
redrawMethod: this.generateOverlayBuffer.bind(this),
|
||||
});
|
||||
|
||||
const dims = globalConfig.mapChunkWorldSize;
|
||||
|
||||
// Draw chunk "pixel" art
|
||||
parameters.context.imageSmoothingEnabled = false;
|
||||
drawSpriteClipped({
|
||||
parameters,
|
||||
sprite,
|
||||
x: this.x * dims,
|
||||
y: this.y * dims,
|
||||
w: dims,
|
||||
h: dims,
|
||||
originalW: overlaySize,
|
||||
originalH: overlaySize,
|
||||
});
|
||||
|
||||
parameters.context.imageSmoothingEnabled = true;
|
||||
|
||||
// Draw patch items
|
||||
if (this.root.currentLayer === "regular") {
|
||||
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);
|
||||
|
||||
patch.item.drawItemCenteredClipped(destX, destY, parameters, diameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {HTMLCanvasElement} canvas
|
||||
* @param {CanvasRenderingContext2D} context
|
||||
* @param {number} w
|
||||
* @param {number} h
|
||||
* @param {number} dpi
|
||||
*/
|
||||
generateOverlayBuffer(canvas, context, w, h, dpi) {
|
||||
context.fillStyle =
|
||||
this.containedEntities.length > 0
|
||||
? THEME.map.chunkOverview.filled
|
||||
: THEME.map.chunkOverview.empty;
|
||||
context.fillRect(0, 0, w, h);
|
||||
|
||||
for (let x = 0; x < globalConfig.mapChunkSize; ++x) {
|
||||
const lowerArray = this.lowerLayer[x];
|
||||
const upperArray = this.contents[x];
|
||||
for (let y = 0; y < globalConfig.mapChunkSize; ++y) {
|
||||
const upperContent = upperArray[y];
|
||||
if (upperContent) {
|
||||
const staticComp = upperContent.components.StaticMapEntity;
|
||||
const data = getBuildingDataFromCode(staticComp.code);
|
||||
const metaBuilding = data.metaInstance;
|
||||
|
||||
const overlayMatrix = metaBuilding.getSpecialOverlayRenderMatrix(
|
||||
staticComp.rotation,
|
||||
data.rotationVariant,
|
||||
data.variant,
|
||||
upperContent
|
||||
);
|
||||
|
||||
if (overlayMatrix) {
|
||||
// Draw lower content first since it "shines" through
|
||||
const lowerContent = lowerArray[y];
|
||||
if (lowerContent) {
|
||||
context.fillStyle = lowerContent.getBackgroundColorAsResource();
|
||||
context.fillRect(
|
||||
x * CHUNK_OVERLAY_RES,
|
||||
y * CHUNK_OVERLAY_RES,
|
||||
CHUNK_OVERLAY_RES,
|
||||
CHUNK_OVERLAY_RES
|
||||
);
|
||||
}
|
||||
|
||||
context.fillStyle = metaBuilding.getSilhouetteColor();
|
||||
for (let dx = 0; dx < 3; ++dx) {
|
||||
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,
|
||||
1,
|
||||
1
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
} else {
|
||||
context.fillStyle = metaBuilding.getSilhouetteColor();
|
||||
context.fillRect(
|
||||
x * CHUNK_OVERLAY_RES,
|
||||
y * CHUNK_OVERLAY_RES,
|
||||
CHUNK_OVERLAY_RES,
|
||||
CHUNK_OVERLAY_RES
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const lowerContent = lowerArray[y];
|
||||
if (lowerContent) {
|
||||
context.fillStyle = lowerContent.getBackgroundColorAsResource();
|
||||
context.fillRect(
|
||||
x * CHUNK_OVERLAY_RES,
|
||||
y * CHUNK_OVERLAY_RES,
|
||||
CHUNK_OVERLAY_RES,
|
||||
CHUNK_OVERLAY_RES
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.root.currentLayer === "wires") {
|
||||
// Draw wires overlay
|
||||
|
||||
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];
|
||||
for (let y = 0; y < globalConfig.mapChunkSize; ++y) {
|
||||
const content = wiresArray[y];
|
||||
if (!content) {
|
||||
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
|
||||
*/
|
||||
static drawSingleWiresOverviewTile({ context, x, y, entity, tileSizePixels, overrideColor = null }) {
|
||||
const staticComp = entity.components.StaticMapEntity;
|
||||
const data = getBuildingDataFromCode(staticComp.code);
|
||||
const metaBuilding = data.metaInstance;
|
||||
const overlayMatrix = metaBuilding.getSpecialOverlayRenderMatrix(
|
||||
staticComp.rotation,
|
||||
data.rotationVariant,
|
||||
data.variant,
|
||||
entity
|
||||
);
|
||||
context.fillStyle = overrideColor || metaBuilding.getSilhouetteColor();
|
||||
if (overlayMatrix) {
|
||||
for (let dx = 0; dx < 3; ++dx) {
|
||||
for (let dy = 0; dy < 3; ++dy) {
|
||||
const isFilled = overlayMatrix[dx + dy * 3];
|
||||
if (isFilled) {
|
||||
context.fillRect(
|
||||
x + (dx * tileSizePixels) / CHUNK_OVERLAY_RES,
|
||||
y + (dy * tileSizePixels) / CHUNK_OVERLAY_RES,
|
||||
tileSizePixels / CHUNK_OVERLAY_RES,
|
||||
tileSizePixels / CHUNK_OVERLAY_RES
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
context.fillRect(x, y, tileSizePixels, tileSizePixels);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
import { globalConfig } from "../core/config";
|
||||
import { DrawParameters } from "../core/draw_parameters";
|
||||
import { getBuildingDataFromCode } from "./building_codes";
|
||||
import { Entity } from "./entity";
|
||||
import { MapChunk } from "./map_chunk";
|
||||
import { GameRoot } from "./root";
|
||||
import { THEME } from "./theme";
|
||||
import { drawSpriteClipped } from "../core/draw_utils";
|
||||
|
||||
export const CHUNK_OVERLAY_RES = 3;
|
||||
|
||||
export class MapChunkView extends MapChunk {
|
||||
/**
|
||||
*
|
||||
* @param {GameRoot} root
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
*/
|
||||
constructor(root, x, y) {
|
||||
super(root, x, y);
|
||||
|
||||
/**
|
||||
* Whenever something changes, we increase this number - so we know we need to redraw
|
||||
*/
|
||||
this.renderIteration = 0;
|
||||
|
||||
this.markDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this chunk as dirty, rerendering all caches
|
||||
*/
|
||||
markDirty() {
|
||||
++this.renderIteration;
|
||||
this.renderKey = this.x + "/" + this.y + "@" + this.renderIteration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the background layer
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawBackgroundLayer(parameters) {
|
||||
const systems = this.root.systemMgr.systems;
|
||||
systems.mapResources.drawChunk(parameters, this);
|
||||
systems.beltUnderlays.drawChunk(parameters, this);
|
||||
systems.belt.drawChunk(parameters, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the dynamic foreground layer
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawForegroundDynamicLayer(parameters) {
|
||||
const systems = this.root.systemMgr.systems;
|
||||
|
||||
systems.itemEjector.drawChunk(parameters, this);
|
||||
systems.itemAcceptor.drawChunk(parameters, this);
|
||||
systems.miner.drawChunk(parameters, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the static foreground layer
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawForegroundStaticLayer(parameters) {
|
||||
const systems = this.root.systemMgr.systems;
|
||||
|
||||
systems.staticMapEntities.drawChunk(parameters, this);
|
||||
systems.lever.drawChunk(parameters, this);
|
||||
systems.display.drawChunk(parameters, this);
|
||||
systems.storage.drawChunk(parameters, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overlay
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawOverlay(parameters) {
|
||||
const overlaySize = globalConfig.mapChunkSize * CHUNK_OVERLAY_RES;
|
||||
const sprite = this.root.buffers.getForKey({
|
||||
key: "chunk@" + this.root.currentLayer,
|
||||
subKey: this.renderKey,
|
||||
w: overlaySize,
|
||||
h: overlaySize,
|
||||
dpi: 1,
|
||||
redrawMethod: this.generateOverlayBuffer.bind(this),
|
||||
});
|
||||
|
||||
const dims = globalConfig.mapChunkWorldSize;
|
||||
|
||||
// Draw chunk "pixel" art
|
||||
parameters.context.imageSmoothingEnabled = false;
|
||||
drawSpriteClipped({
|
||||
parameters,
|
||||
sprite,
|
||||
x: this.x * dims,
|
||||
y: this.y * dims,
|
||||
w: dims,
|
||||
h: dims,
|
||||
originalW: overlaySize,
|
||||
originalH: overlaySize,
|
||||
});
|
||||
|
||||
parameters.context.imageSmoothingEnabled = true;
|
||||
|
||||
// Draw patch items
|
||||
if (this.root.currentLayer === "regular") {
|
||||
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);
|
||||
|
||||
patch.item.drawItemCenteredClipped(destX, destY, parameters, diameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {HTMLCanvasElement} canvas
|
||||
* @param {CanvasRenderingContext2D} context
|
||||
* @param {number} w
|
||||
* @param {number} h
|
||||
* @param {number} dpi
|
||||
*/
|
||||
generateOverlayBuffer(canvas, context, w, h, dpi) {
|
||||
context.fillStyle =
|
||||
this.containedEntities.length > 0
|
||||
? THEME.map.chunkOverview.filled
|
||||
: THEME.map.chunkOverview.empty;
|
||||
context.fillRect(0, 0, w, h);
|
||||
|
||||
for (let x = 0; x < globalConfig.mapChunkSize; ++x) {
|
||||
const lowerArray = this.lowerLayer[x];
|
||||
const upperArray = this.contents[x];
|
||||
for (let y = 0; y < globalConfig.mapChunkSize; ++y) {
|
||||
const upperContent = upperArray[y];
|
||||
if (upperContent) {
|
||||
const staticComp = upperContent.components.StaticMapEntity;
|
||||
const data = getBuildingDataFromCode(staticComp.code);
|
||||
const metaBuilding = data.metaInstance;
|
||||
|
||||
const overlayMatrix = metaBuilding.getSpecialOverlayRenderMatrix(
|
||||
staticComp.rotation,
|
||||
data.rotationVariant,
|
||||
data.variant,
|
||||
upperContent
|
||||
);
|
||||
|
||||
if (overlayMatrix) {
|
||||
// Draw lower content first since it "shines" through
|
||||
const lowerContent = lowerArray[y];
|
||||
if (lowerContent) {
|
||||
context.fillStyle = lowerContent.getBackgroundColorAsResource();
|
||||
context.fillRect(
|
||||
x * CHUNK_OVERLAY_RES,
|
||||
y * CHUNK_OVERLAY_RES,
|
||||
CHUNK_OVERLAY_RES,
|
||||
CHUNK_OVERLAY_RES
|
||||
);
|
||||
}
|
||||
|
||||
context.fillStyle = metaBuilding.getSilhouetteColor();
|
||||
for (let dx = 0; dx < 3; ++dx) {
|
||||
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,
|
||||
1,
|
||||
1
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
} else {
|
||||
context.fillStyle = metaBuilding.getSilhouetteColor();
|
||||
context.fillRect(
|
||||
x * CHUNK_OVERLAY_RES,
|
||||
y * CHUNK_OVERLAY_RES,
|
||||
CHUNK_OVERLAY_RES,
|
||||
CHUNK_OVERLAY_RES
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const lowerContent = lowerArray[y];
|
||||
if (lowerContent) {
|
||||
context.fillStyle = lowerContent.getBackgroundColorAsResource();
|
||||
context.fillRect(
|
||||
x * CHUNK_OVERLAY_RES,
|
||||
y * CHUNK_OVERLAY_RES,
|
||||
CHUNK_OVERLAY_RES,
|
||||
CHUNK_OVERLAY_RES
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.root.currentLayer === "wires") {
|
||||
// Draw wires overlay
|
||||
|
||||
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];
|
||||
for (let y = 0; y < globalConfig.mapChunkSize; ++y) {
|
||||
const content = wiresArray[y];
|
||||
if (!content) {
|
||||
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
|
||||
*/
|
||||
static drawSingleWiresOverviewTile({ context, x, y, entity, tileSizePixels, overrideColor = null }) {
|
||||
const staticComp = entity.components.StaticMapEntity;
|
||||
const data = getBuildingDataFromCode(staticComp.code);
|
||||
const metaBuilding = data.metaInstance;
|
||||
const overlayMatrix = metaBuilding.getSpecialOverlayRenderMatrix(
|
||||
staticComp.rotation,
|
||||
data.rotationVariant,
|
||||
data.variant,
|
||||
entity
|
||||
);
|
||||
context.fillStyle = overrideColor || metaBuilding.getSilhouetteColor();
|
||||
if (overlayMatrix) {
|
||||
for (let dx = 0; dx < 3; ++dx) {
|
||||
for (let dy = 0; dy < 3; ++dy) {
|
||||
const isFilled = overlayMatrix[dx + dy * 3];
|
||||
if (isFilled) {
|
||||
context.fillRect(
|
||||
x + (dx * tileSizePixels) / CHUNK_OVERLAY_RES,
|
||||
y + (dy * tileSizePixels) / CHUNK_OVERLAY_RES,
|
||||
tileSizePixels / CHUNK_OVERLAY_RES,
|
||||
tileSizePixels / CHUNK_OVERLAY_RES
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
context.fillRect(x, y, tileSizePixels, tileSizePixels);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
@ -1,252 +1,253 @@
|
||||
import { globalConfig } from "../core/config";
|
||||
import { DrawParameters } from "../core/draw_parameters";
|
||||
import { BaseMap } from "./map";
|
||||
import { freeCanvas, makeOffscreenBuffer } from "../core/buffer_utils";
|
||||
import { Entity } from "./entity";
|
||||
import { THEME } from "./theme";
|
||||
import { MapChunkView } from "./map_chunk_view";
|
||||
|
||||
/**
|
||||
* This is the view of the map, it extends the map which is the raw model and allows
|
||||
* to draw it
|
||||
*/
|
||||
export class MapView extends BaseMap {
|
||||
constructor(root) {
|
||||
super(root);
|
||||
|
||||
/**
|
||||
* DPI of the background cache images, required in some places
|
||||
*/
|
||||
this.backgroundCacheDPI = 2;
|
||||
|
||||
/**
|
||||
* The cached background sprite, containing the flat background
|
||||
* @type {HTMLCanvasElement} */
|
||||
this.cachedBackgroundCanvas = null;
|
||||
|
||||
/** @type {CanvasRenderingContext2D} */
|
||||
this.cachedBackgroundContext = null;
|
||||
/**
|
||||
* Cached pattern of the stripes background
|
||||
* @type {CanvasPattern} */
|
||||
this.cachedBackgroundPattern = null;
|
||||
|
||||
this.internalInitializeCachedBackgroundCanvases();
|
||||
this.root.signals.aboutToDestruct.add(this.cleanup, this);
|
||||
|
||||
this.root.signals.entityAdded.add(this.onEntityChanged, this);
|
||||
this.root.signals.entityDestroyed.add(this.onEntityChanged, this);
|
||||
this.root.signals.entityChanged.add(this.onEntityChanged, this);
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
freeCanvas(this.cachedBackgroundCanvas);
|
||||
this.cachedBackgroundCanvas = null;
|
||||
this.cachedBackgroundPattern = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an entity was added, removed or changed
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
onEntityChanged(entity) {
|
||||
const staticComp = entity.components.StaticMapEntity;
|
||||
if (staticComp) {
|
||||
const rect = staticComp.getTileSpaceBounds();
|
||||
for (let x = rect.x; x <= rect.right(); ++x) {
|
||||
for (let y = rect.y; y <= rect.bottom(); ++y) {
|
||||
this.root.map.getOrCreateChunkAtTile(x, y).markDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws all static entities like buildings etc.
|
||||
* @param {DrawParameters} drawParameters
|
||||
*/
|
||||
drawStaticEntityDebugOverlays(drawParameters) {
|
||||
const cullRange = drawParameters.visibleRect.toTileCullRectangle();
|
||||
const top = cullRange.top();
|
||||
const right = cullRange.right();
|
||||
const bottom = cullRange.bottom();
|
||||
const left = cullRange.left();
|
||||
|
||||
const border = 1;
|
||||
|
||||
const minY = top - border;
|
||||
const maxY = bottom + border;
|
||||
const minX = left - border;
|
||||
const maxX = right + border - 1;
|
||||
|
||||
// Render y from top down for proper blending
|
||||
for (let y = minY; y <= maxY; ++y) {
|
||||
for (let x = minX; x <= maxX; ++x) {
|
||||
// const content = this.tiles[x][y];
|
||||
const chunk = this.getChunkAtTileOrNull(x, y);
|
||||
if (!chunk) {
|
||||
continue;
|
||||
}
|
||||
const content = chunk.getTileContentFromWorldCoords(x, y);
|
||||
if (content) {
|
||||
let isBorder = x <= left - 1 || x >= right + 1 || y <= top - 1 || y >= bottom + 1;
|
||||
if (!isBorder) {
|
||||
content.drawDebugOverlays(drawParameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes all canvases used for background rendering
|
||||
*/
|
||||
internalInitializeCachedBackgroundCanvases() {
|
||||
// Background canvas
|
||||
const dims = globalConfig.tileSize;
|
||||
const dpi = this.backgroundCacheDPI;
|
||||
const [canvas, context] = makeOffscreenBuffer(dims * dpi, dims * dpi, {
|
||||
smooth: false,
|
||||
label: "map-cached-bg",
|
||||
});
|
||||
context.scale(dpi, dpi);
|
||||
|
||||
context.fillStyle = THEME.map.background;
|
||||
context.fillRect(0, 0, dims, dims);
|
||||
|
||||
const borderWidth = THEME.map.gridLineWidth;
|
||||
context.fillStyle = THEME.map.grid;
|
||||
context.fillRect(0, 0, dims, borderWidth);
|
||||
context.fillRect(0, borderWidth, borderWidth, dims);
|
||||
|
||||
context.fillRect(dims - borderWidth, borderWidth, borderWidth, dims - 2 * borderWidth);
|
||||
context.fillRect(borderWidth, dims - borderWidth, dims, borderWidth);
|
||||
|
||||
this.cachedBackgroundCanvas = canvas;
|
||||
this.cachedBackgroundContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the maps foreground
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawForeground(parameters) {
|
||||
this.drawVisibleChunks(parameters, MapChunkView.prototype.drawForegroundLayer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a given method on all given chunks
|
||||
* @param {DrawParameters} parameters
|
||||
* @param {function} method
|
||||
*/
|
||||
drawVisibleChunks(parameters, method) {
|
||||
const cullRange = parameters.visibleRect.allScaled(1 / globalConfig.tileSize);
|
||||
const top = cullRange.top();
|
||||
const right = cullRange.right();
|
||||
const bottom = cullRange.bottom();
|
||||
const left = cullRange.left();
|
||||
|
||||
const border = 0;
|
||||
const minY = top - border;
|
||||
const maxY = bottom + border;
|
||||
const minX = left - border;
|
||||
const maxX = right + border;
|
||||
|
||||
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);
|
||||
|
||||
// Render y from top down for proper blending
|
||||
for (let chunkX = chunkStartX; chunkX <= chunkEndX; ++chunkX) {
|
||||
for (let chunkY = chunkStartY; chunkY <= chunkEndY; ++chunkY) {
|
||||
const chunk = this.root.map.getChunk(chunkX, chunkY, true);
|
||||
method.call(chunk, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the wires foreground
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawWiresForegroundLayer(parameters) {
|
||||
this.drawVisibleChunks(parameters, MapChunkView.prototype.drawWiresForegroundLayer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the map overlay
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawOverlay(parameters) {
|
||||
this.drawVisibleChunks(parameters, MapChunkView.prototype.drawOverlay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the map background
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawBackground(parameters) {
|
||||
if (!this.cachedBackgroundPattern) {
|
||||
this.cachedBackgroundPattern = parameters.context.createPattern(
|
||||
this.cachedBackgroundCanvas,
|
||||
"repeat"
|
||||
);
|
||||
}
|
||||
|
||||
if (!this.root.app.settings.getAllSettings().disableTileGrid) {
|
||||
const dpi = this.backgroundCacheDPI;
|
||||
parameters.context.scale(1 / dpi, 1 / dpi);
|
||||
|
||||
parameters.context.fillStyle = this.cachedBackgroundPattern;
|
||||
parameters.context.fillRect(
|
||||
parameters.visibleRect.x * dpi,
|
||||
parameters.visibleRect.y * dpi,
|
||||
parameters.visibleRect.w * dpi,
|
||||
parameters.visibleRect.h * dpi
|
||||
);
|
||||
parameters.context.scale(dpi, dpi);
|
||||
}
|
||||
|
||||
this.drawVisibleChunks(parameters, MapChunkView.prototype.drawBackgroundLayer);
|
||||
|
||||
if (G_IS_DEV && globalConfig.debug.showChunkBorders) {
|
||||
const cullRange = parameters.visibleRect.toTileCullRectangle();
|
||||
const top = cullRange.top();
|
||||
const right = cullRange.right();
|
||||
const bottom = cullRange.bottom();
|
||||
const left = cullRange.left();
|
||||
|
||||
const border = 1;
|
||||
const minY = top - border;
|
||||
const maxY = bottom + border;
|
||||
const minX = left - border;
|
||||
const maxX = right + border - 1;
|
||||
|
||||
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);
|
||||
|
||||
for (let chunkX = chunkStartX; chunkX <= chunkEndX; ++chunkX) {
|
||||
for (let chunkY = chunkStartY; chunkY <= chunkEndY; ++chunkY) {
|
||||
parameters.context.fillStyle = "#ffaaaa";
|
||||
parameters.context.fillRect(
|
||||
chunkX * globalConfig.mapChunkWorldSize,
|
||||
chunkY * globalConfig.mapChunkWorldSize,
|
||||
globalConfig.mapChunkWorldSize,
|
||||
3
|
||||
);
|
||||
parameters.context.fillRect(
|
||||
chunkX * globalConfig.mapChunkWorldSize,
|
||||
chunkY * globalConfig.mapChunkWorldSize,
|
||||
3,
|
||||
globalConfig.mapChunkWorldSize
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
import { globalConfig } from "../core/config";
|
||||
import { DrawParameters } from "../core/draw_parameters";
|
||||
import { BaseMap } from "./map";
|
||||
import { freeCanvas, makeOffscreenBuffer } from "../core/buffer_utils";
|
||||
import { Entity } from "./entity";
|
||||
import { THEME } from "./theme";
|
||||
import { MapChunkView } from "./map_chunk_view";
|
||||
|
||||
/**
|
||||
* This is the view of the map, it extends the map which is the raw model and allows
|
||||
* to draw it
|
||||
*/
|
||||
export class MapView extends BaseMap {
|
||||
constructor(root) {
|
||||
super(root);
|
||||
|
||||
/**
|
||||
* DPI of the background cache images, required in some places
|
||||
*/
|
||||
this.backgroundCacheDPI = 2;
|
||||
|
||||
/**
|
||||
* The cached background sprite, containing the flat background
|
||||
* @type {HTMLCanvasElement} */
|
||||
this.cachedBackgroundCanvas = null;
|
||||
|
||||
/** @type {CanvasRenderingContext2D} */
|
||||
this.cachedBackgroundContext = null;
|
||||
/**
|
||||
* Cached pattern of the stripes background
|
||||
* @type {CanvasPattern} */
|
||||
this.cachedBackgroundPattern = null;
|
||||
|
||||
this.internalInitializeCachedBackgroundCanvases();
|
||||
this.root.signals.aboutToDestruct.add(this.cleanup, this);
|
||||
|
||||
this.root.signals.entityAdded.add(this.onEntityChanged, this);
|
||||
this.root.signals.entityDestroyed.add(this.onEntityChanged, this);
|
||||
this.root.signals.entityChanged.add(this.onEntityChanged, this);
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
freeCanvas(this.cachedBackgroundCanvas);
|
||||
this.cachedBackgroundCanvas = null;
|
||||
this.cachedBackgroundPattern = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an entity was added, removed or changed
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
onEntityChanged(entity) {
|
||||
const staticComp = entity.components.StaticMapEntity;
|
||||
if (staticComp) {
|
||||
const rect = staticComp.getTileSpaceBounds();
|
||||
for (let x = rect.x; x <= rect.right(); ++x) {
|
||||
for (let y = rect.y; y <= rect.bottom(); ++y) {
|
||||
this.root.map.getOrCreateChunkAtTile(x, y).markDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws all static entities like buildings etc.
|
||||
* @param {DrawParameters} drawParameters
|
||||
*/
|
||||
drawStaticEntityDebugOverlays(drawParameters) {
|
||||
const cullRange = drawParameters.visibleRect.toTileCullRectangle();
|
||||
const top = cullRange.top();
|
||||
const right = cullRange.right();
|
||||
const bottom = cullRange.bottom();
|
||||
const left = cullRange.left();
|
||||
|
||||
const border = 1;
|
||||
|
||||
const minY = top - border;
|
||||
const maxY = bottom + border;
|
||||
const minX = left - border;
|
||||
const maxX = right + border - 1;
|
||||
|
||||
// Render y from top down for proper blending
|
||||
for (let y = minY; y <= maxY; ++y) {
|
||||
for (let x = minX; x <= maxX; ++x) {
|
||||
// const content = this.tiles[x][y];
|
||||
const chunk = this.getChunkAtTileOrNull(x, y);
|
||||
if (!chunk) {
|
||||
continue;
|
||||
}
|
||||
const content = chunk.getTileContentFromWorldCoords(x, y);
|
||||
if (content) {
|
||||
let isBorder = x <= left - 1 || x >= right + 1 || y <= top - 1 || y >= bottom + 1;
|
||||
if (!isBorder) {
|
||||
content.drawDebugOverlays(drawParameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes all canvases used for background rendering
|
||||
*/
|
||||
internalInitializeCachedBackgroundCanvases() {
|
||||
// Background canvas
|
||||
const dims = globalConfig.tileSize;
|
||||
const dpi = this.backgroundCacheDPI;
|
||||
const [canvas, context] = makeOffscreenBuffer(dims * dpi, dims * dpi, {
|
||||
smooth: false,
|
||||
label: "map-cached-bg",
|
||||
});
|
||||
context.scale(dpi, dpi);
|
||||
|
||||
context.fillStyle = THEME.map.background;
|
||||
context.fillRect(0, 0, dims, dims);
|
||||
|
||||
const borderWidth = THEME.map.gridLineWidth;
|
||||
context.fillStyle = THEME.map.grid;
|
||||
context.fillRect(0, 0, dims, borderWidth);
|
||||
context.fillRect(0, borderWidth, borderWidth, dims);
|
||||
|
||||
context.fillRect(dims - borderWidth, borderWidth, borderWidth, dims - 2 * borderWidth);
|
||||
context.fillRect(borderWidth, dims - borderWidth, dims, borderWidth);
|
||||
|
||||
this.cachedBackgroundCanvas = canvas;
|
||||
this.cachedBackgroundContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the maps foreground
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawForeground(parameters) {
|
||||
this.drawVisibleChunks(parameters, MapChunkView.prototype.drawForegroundDynamicLayer);
|
||||
this.drawVisibleChunks(parameters, MapChunkView.prototype.drawForegroundStaticLayer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a given method on all given chunks
|
||||
* @param {DrawParameters} parameters
|
||||
* @param {function} method
|
||||
*/
|
||||
drawVisibleChunks(parameters, method) {
|
||||
const cullRange = parameters.visibleRect.allScaled(1 / globalConfig.tileSize);
|
||||
const top = cullRange.top();
|
||||
const right = cullRange.right();
|
||||
const bottom = cullRange.bottom();
|
||||
const left = cullRange.left();
|
||||
|
||||
const border = 0;
|
||||
const minY = top - border;
|
||||
const maxY = bottom + border;
|
||||
const minX = left - border;
|
||||
const maxX = right + border;
|
||||
|
||||
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);
|
||||
|
||||
// Render y from top down for proper blending
|
||||
for (let chunkX = chunkStartX; chunkX <= chunkEndX; ++chunkX) {
|
||||
for (let chunkY = chunkStartY; chunkY <= chunkEndY; ++chunkY) {
|
||||
const chunk = this.root.map.getChunk(chunkX, chunkY, true);
|
||||
method.call(chunk, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the wires foreground
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawWiresForegroundLayer(parameters) {
|
||||
this.drawVisibleChunks(parameters, MapChunkView.prototype.drawWiresForegroundLayer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the map overlay
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawOverlay(parameters) {
|
||||
this.drawVisibleChunks(parameters, MapChunkView.prototype.drawOverlay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the map background
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawBackground(parameters) {
|
||||
if (!this.cachedBackgroundPattern) {
|
||||
this.cachedBackgroundPattern = parameters.context.createPattern(
|
||||
this.cachedBackgroundCanvas,
|
||||
"repeat"
|
||||
);
|
||||
}
|
||||
|
||||
if (!this.root.app.settings.getAllSettings().disableTileGrid) {
|
||||
const dpi = this.backgroundCacheDPI;
|
||||
parameters.context.scale(1 / dpi, 1 / dpi);
|
||||
|
||||
parameters.context.fillStyle = this.cachedBackgroundPattern;
|
||||
parameters.context.fillRect(
|
||||
parameters.visibleRect.x * dpi,
|
||||
parameters.visibleRect.y * dpi,
|
||||
parameters.visibleRect.w * dpi,
|
||||
parameters.visibleRect.h * dpi
|
||||
);
|
||||
parameters.context.scale(dpi, dpi);
|
||||
}
|
||||
|
||||
this.drawVisibleChunks(parameters, MapChunkView.prototype.drawBackgroundLayer);
|
||||
|
||||
if (G_IS_DEV && globalConfig.debug.showChunkBorders) {
|
||||
const cullRange = parameters.visibleRect.toTileCullRectangle();
|
||||
const top = cullRange.top();
|
||||
const right = cullRange.right();
|
||||
const bottom = cullRange.bottom();
|
||||
const left = cullRange.left();
|
||||
|
||||
const border = 1;
|
||||
const minY = top - border;
|
||||
const maxY = bottom + border;
|
||||
const minX = left - border;
|
||||
const maxX = right + border - 1;
|
||||
|
||||
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);
|
||||
|
||||
for (let chunkX = chunkStartX; chunkX <= chunkEndX; ++chunkX) {
|
||||
for (let chunkY = chunkStartY; chunkY <= chunkEndY; ++chunkY) {
|
||||
parameters.context.fillStyle = "#ffaaaa";
|
||||
parameters.context.fillRect(
|
||||
chunkX * globalConfig.mapChunkWorldSize,
|
||||
chunkY * globalConfig.mapChunkWorldSize,
|
||||
globalConfig.mapChunkWorldSize,
|
||||
3
|
||||
);
|
||||
parameters.context.fillRect(
|
||||
chunkX * globalConfig.mapChunkWorldSize,
|
||||
chunkY * globalConfig.mapChunkWorldSize,
|
||||
3,
|
||||
globalConfig.mapChunkWorldSize
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user