diff --git a/src/css/ingame_hud/dialogs.scss b/src/css/ingame_hud/dialogs.scss
index 35d9aeb0..b913ba35 100644
--- a/src/css/ingame_hud/dialogs.scss
+++ b/src/css/ingame_hud/dialogs.scss
@@ -226,6 +226,18 @@
}
}
+ .checkBoxGridFormElem {
+ display: inline-grid;
+ grid-template-columns: 1fr;
+ @include S(margin, 10px, 0);
+ @include S(grid-row-gap, 10px);
+
+ > .checkBoxFormElem {
+ margin: 0;
+ justify-content: space-between;
+ }
+ }
+
.enum {
display: grid;
grid-template-columns: auto 1fr auto;
diff --git a/src/js/core/modal_dialog_forms.js b/src/js/core/modal_dialog_forms.js
index 2f2401a9..b27204f3 100644
--- a/src/js/core/modal_dialog_forms.js
+++ b/src/js/core/modal_dialog_forms.js
@@ -140,7 +140,7 @@ export class FormElementCheckbox extends FormElement {
getHtml() {
return `
- ${this.label ? `
` : ""}
+ ${this.label ? `
` : ""}
@@ -170,6 +170,31 @@ export class FormElementCheckbox extends FormElement {
focus(parent) {}
}
+export class FormElementCheckboxList extends FormElement {
+ constructor({ id, label = null, checkboxes = [] }) {
+ super(id, label);
+ this.checkboxes = checkboxes;
+ }
+
+ getHtml() {
+ return `
+
+ ${this.checkboxes.map(checkbox => checkbox.getHtml()).join("\n")}
+
+ `;
+ }
+
+ bindEvents(parent, clickTrackers) {
+ this.checkboxes.forEach(checkbox => checkbox.bindEvents(parent, clickTrackers));
+ }
+
+ getValue() {
+ return this.checkboxes.map(checkbox => checkbox.getValue());
+ }
+
+ focus(parent) {}
+}
+
export class FormElementItemChooser extends FormElement {
/**
*
diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js
index 673dc9cd..0ec46069 100644
--- a/src/js/game/hud/parts/screenshot_exporter.js
+++ b/src/js/game/hud/parts/screenshot_exporter.js
@@ -9,12 +9,16 @@ import { StaticMapEntityComponent } from "../../components/static_map_entity";
import { KEYMAPPINGS } from "../../key_action_mapper";
import { BaseHUDPart } from "../base_hud_part";
import { DialogWithForm } from "../../../core/modal_dialog_elements";
-import { FormElementCheckbox, FormElementEnum } from "../../../core/modal_dialog_forms";
+import {
+ FormElementCheckbox,
+ FormElementCheckboxList,
+ FormElementEnum,
+} from "../../../core/modal_dialog_forms";
import { ORIGINAL_SPRITE_SCALE } from "../../../core/sprites";
import { getDeviceDPI } from "../../../core/dpi_manager";
import { HUDMassSelector } from "./mass_selector";
import { clamp } from "../../../core/utils";
-import { CHUNK_OVERLAY_RES } from "../../map_chunk_view";
+import { CHUNK_OVERLAY_RES, MapChunkView } from "../../map_chunk_view";
const logger = createLogger("screenshot_exporter");
@@ -113,6 +117,16 @@ export class HUDScreenshotExporter extends BaseHUDPart {
label: "Wires layer",
defaultValue: this.root.currentLayer === "wires" ? true : false,
});
+ const backgroundInput = new FormElementCheckbox({
+ id: "screenshotBackground",
+ // @TODO: translation (T.dialogs.exportScreenshotWarning.descBackground)
+ label: "Transparent background",
+ defaultValue: false,
+ });
+ const checkboxInputs = new FormElementCheckboxList({
+ id: "screenshotCheckboxes",
+ checkboxes: [overlayInput, layerInput, backgroundInput],
+ });
const dialog = new DialogWithForm({
app: this.root.app,
title: T.dialogs.exportScreenshotWarning.title,
@@ -128,7 +142,7 @@ export class HUDScreenshotExporter extends BaseHUDPart {
.getKeyCodeString() +
""
),
- formElements: [qualityInput, overlayInput, layerInput],
+ formElements: [qualityInput, checkboxInputs],
buttons: ["cancel:good", "ok:bad"],
});
@@ -145,6 +159,7 @@ export class HUDScreenshotExporter extends BaseHUDPart {
qualityInput.getValue(),
overlayInput.getValue(),
layerInput.getValue(),
+ backgroundInput.getValue(),
!!bounds,
bounds
),
@@ -157,10 +172,11 @@ export class HUDScreenshotExporter extends BaseHUDPart {
* @param {number} targetResolution
* @param {boolean} overlay
* @param {boolean} wiresLayer
+ * @param {boolean} hideBackground
* @param {boolean} allowBorder
* @param {Rectangle?} tileBounds
*/
- doExport(targetResolution, overlay, wiresLayer, allowBorder, tileBounds) {
+ doExport(targetResolution, overlay, wiresLayer, hideBackground, allowBorder, tileBounds) {
logger.log("Starting export ...");
const boundsSelected = !!tileBounds;
@@ -296,9 +312,23 @@ export class HUDScreenshotExporter extends BaseHUDPart {
this.root.signals.gameFrameStarted.dispatch();
if (overlay) {
this.root;
- this.root.map.drawOverlay(parameters);
+ if (hideBackground) {
+ this.root.map.drawVisibleChunks(parameters, MapChunkView.prototype.drawOverlayNoBackground);
+ } else {
+ this.root.map.drawOverlay(parameters);
+ }
} else {
- this.root.map.drawBackground(parameters);
+ if (hideBackground) {
+ this.root.map.drawVisibleChunks(
+ parameters,
+ /** @this {MapChunkView} */ function (parameters) {
+ this.root.systemMgr.systems.beltUnderlays.drawChunk(parameters, this);
+ this.root.systemMgr.systems.belt.drawChunk(parameters, this);
+ }
+ );
+ } else {
+ this.root.map.drawBackground(parameters);
+ }
this.root.systemMgr.systems.belt.drawBeltItems(parameters);
this.root.map.drawForeground(parameters);
this.root.systemMgr.systems.hub.draw(parameters);
diff --git a/src/js/game/map_chunk_view.js b/src/js/game/map_chunk_view.js
index 131ce37b..cc5c43d9 100644
--- a/src/js/game/map_chunk_view.js
+++ b/src/js/game/map_chunk_view.js
@@ -130,6 +130,40 @@ export class MapChunkView extends MapChunk {
}
}
+ /**
+ * Overlay with transparent background
+ * @param {DrawParameters} parameters
+ */
+ drawOverlayNoBackground(parameters) {
+ const overlaySize = globalConfig.mapChunkSize * CHUNK_OVERLAY_RES;
+ const sprite = this.root.buffers.getForKey({
+ key: "chunknobg@" + this.root.currentLayer,
+ subKey: this.renderKey,
+ w: overlaySize,
+ h: overlaySize,
+ dpi: 1,
+ redrawMethod: this.generateOverlayBufferNoBackground.bind(this),
+ });
+
+ const dims = globalConfig.mapChunkWorldSize;
+ const extrude = 0.05;
+
+ // Draw chunk "pixel" art
+ parameters.context.imageSmoothingEnabled = false;
+ drawSpriteClipped({
+ parameters,
+ sprite,
+ x: this.x * dims - extrude,
+ y: this.y * dims - extrude,
+ w: dims + 2 * extrude,
+ h: dims + 2 * extrude,
+ originalW: overlaySize,
+ originalH: overlaySize,
+ });
+
+ parameters.context.imageSmoothingEnabled = true;
+ }
+
/**
*
* @param {HTMLCanvasElement} canvas
@@ -254,6 +288,94 @@ export class MapChunkView extends MapChunk {
}
}
+ /**
+ *
+ * @param {HTMLCanvasElement} canvas
+ * @param {CanvasRenderingContext2D} context
+ * @param {number} w
+ * @param {number} h
+ * @param {number} dpi
+ */
+ generateOverlayBufferNoBackground(canvas, context, w, h, dpi) {
+ for (let x = 0; x < globalConfig.mapChunkSize; ++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) {
+ context.fillStyle = metaBuilding.getSilhouetteColor(
+ data.variant,
+ data.rotationVariant
+ );
+ 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(
+ data.variant,
+ data.rotationVariant
+ );
+ context.fillRect(
+ x * CHUNK_OVERLAY_RES,
+ y * CHUNK_OVERLAY_RES,
+ CHUNK_OVERLAY_RES,
+ CHUNK_OVERLAY_RES
+ );
+
+ continue;
+ }
+ }
+ }
+ }
+
+ 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