From da6b1a437c005addc108f526ef500f96fe6e256f Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Fri, 20 Nov 2020 22:07:43 -0600 Subject: [PATCH 01/24] Improve screenshots Now renders shapes and optionally wires layer. The screenshot dialog box gets two options: Whether or not to show the wires layer, and the pixel width of each tile. The bug where onscreen buildings are not rendered is fixed. --- src/js/game/hud/parts/screenshot_exporter.js | 44 ++++++++++++++++---- src/js/game/hud/parts/wires_overlay.js | 7 ++-- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index dd81f8b6..31e90a4f 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -8,6 +8,8 @@ import { T } from "../../../translations"; 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 { FormElementInput, FormElementCheckbox } from "../../../core/modal_dialog_forms"; const logger = createLogger("screenshot_exporter"); @@ -24,15 +26,34 @@ export class HUDScreenshotExporter extends BaseHUDPart { return; } - const { ok } = this.root.hud.parts.dialogs.showInfo( - T.dialogs.exportScreenshotWarning.title, - T.dialogs.exportScreenshotWarning.desc, - ["cancel:good", "ok:bad"] + const layerInput = new FormElementCheckbox({ + id: "screenshotLayer", + label: "Include wires layer", + defaultValue: this.root.currentLayer === "wires" ? true : false, + }); + const qualityInput = new FormElementInput({ + id: "screenshotQuality", + label: "Pixel width per tile", + placeholder: "", + defaultValue: "", + validator: val => !isNaN(val) && parseInt(val) === parseFloat(val) && !isNaN(parseInt(val, 10)), + }); + const dialog = new DialogWithForm({ + app: this.root.app, + title: T.dialogs.exportScreenshotWarning.title, + desc: T.dialogs.exportScreenshotWarning.desc, + formElements: [layerInput, qualityInput], + buttons: ["cancel:good", "ok:bad"], + }); + + this.root.hud.parts.dialogs.internalShowDialog(dialog); + dialog.buttonSignals.ok.add( + () => this.doExport(layerInput.getValue(), qualityInput.getValue()), + this ); - ok.add(this.doExport, this); } - doExport() { + doExport(wiresLayer, quality) { logger.log("Starting export ..."); // Find extends @@ -55,11 +76,11 @@ export class HUDScreenshotExporter extends BaseHUDPart { const dimensions = maxChunk.sub(minChunk); logger.log("Dimensions:", dimensions); - let chunkSizePixels = 128; + let chunkSizePixels = quality * globalConfig.mapChunkSize; const maxDimensions = Math.max(dimensions.x, dimensions.y); if (maxDimensions > 128) { - chunkSizePixels = Math.max(1, Math.floor(128 * (128 / maxDimensions))); + chunkSizePixels = Math.max(1, Math.floor(chunkSizePixels * (128 / maxDimensions))); } logger.log("ChunkSizePixels:", chunkSizePixels); @@ -96,8 +117,15 @@ export class HUDScreenshotExporter extends BaseHUDPart { context.translate(-visibleRect.x, -visibleRect.y); // Render all relevant chunks + this.root.signals.gameFrameStarted.dispatch(); this.root.map.drawBackground(parameters); + this.root.systemMgr.systems.belt.drawBeltItems(parameters); this.root.map.drawForeground(parameters); + this.root.systemMgr.systems.hub.draw(parameters); + if (wiresLayer) { + this.root.hud.parts.wiresOverlay.draw(parameters, true); + this.root.map.drawWiresForegroundLayer(parameters); + } // Offer export logger.log("Rendered buffer, exporting ..."); diff --git a/src/js/game/hud/parts/wires_overlay.js b/src/js/game/hud/parts/wires_overlay.js index 328d6689..7a9b645f 100644 --- a/src/js/game/hud/parts/wires_overlay.js +++ b/src/js/game/hud/parts/wires_overlay.js @@ -114,9 +114,10 @@ export class HUDWiresOverlay extends BaseHUDPart { /** * * @param {DrawParameters} parameters + * @param {boolean=} forced */ - draw(parameters) { - if (this.currentAlpha < 0.02) { + draw(parameters, forced = false) { + if (!forced && this.currentAlpha < 0.02) { return; } @@ -127,7 +128,7 @@ export class HUDWiresOverlay extends BaseHUDPart { const bounds = parameters.visibleRect; - parameters.context.globalAlpha = this.currentAlpha; + parameters.context.globalAlpha = forced ? 1 : this.currentAlpha; const scaleFactor = 1 / wiresBackgroundDpi; parameters.context.globalCompositeOperation = "overlay"; From 96170f8d221dbc9144c16e667c63646254479cb8 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Tue, 16 Mar 2021 20:45:14 -0500 Subject: [PATCH 02/24] Add enum form element and update screenshot dialog The enum form element allows for cycling through a list of options. The screenshot dialog now uses this, and has a list of image qualities. The map quality has not yet been implemented. --- src/css/ingame_hud/dialogs.scss | 47 ++++++++++++++ src/js/core/modal_dialog_forms.js | 54 +++++++++++++++++ src/js/game/hud/parts/screenshot_exporter.js | 64 +++++++++++++++----- 3 files changed, 151 insertions(+), 14 deletions(-) diff --git a/src/css/ingame_hud/dialogs.scss b/src/css/ingame_hud/dialogs.scss index cc742d42..38e359e4 100644 --- a/src/css/ingame_hud/dialogs.scss +++ b/src/css/ingame_hud/dialogs.scss @@ -214,6 +214,53 @@ } } } + + .checkBoxFormElem { + @include S(margin, 10px, 0); + > label { + @include S(margin-right, 10px); + } + display: flex; + align-items: center; + } + + .enum { + @include S(margin, 10px, 0); + display: grid; + grid-template-columns: auto 1fr auto; + @include S(grid-gap, 4px); + @include S(width, 200px); + + > * { + background: #fff; + text-align: center; + pointer-events: all; + cursor: pointer; + @include S(border-radius, $globalBorderRadius); + @include S(padding, 4px); + + transition: background-color 0.12s ease-in-out; + &:hover { + background-color: #fafafa; + } + + @include DarkThemeOverride { + background-color: $darkModeControlsBackground; + color: #ddd; + &:hover { + background-color: darken($darkModeControlsBackground, 2); + } + } + + &.toggle { + @include S(width, 20px); + } + + &.value { + transform: none !important; + } + } + } } > .buttons { diff --git a/src/js/core/modal_dialog_forms.js b/src/js/core/modal_dialog_forms.js index aac81d82..9242c57e 100644 --- a/src/js/core/modal_dialog_forms.js +++ b/src/js/core/modal_dialog_forms.js @@ -1,6 +1,7 @@ import { BaseItem } from "../game/base_item"; import { ClickDetector } from "./click_detector"; import { Signal } from "./signal"; +import { safeModulo } from "./utils"; /* * *************************************************** @@ -235,3 +236,56 @@ export class FormElementItemChooser extends FormElement { focus() {} } + +export class FormElementEnum extends FormElement { + constructor({ id, label = null, options, valueGetter, textGetter }) { + super(id, label); + this.options = options; + this.valueGetter = valueGetter; + this.textGetter = textGetter; + this.index = 0; + + this.element = null; + } + + getHtml() { + return ` +
+ ${this.label ? `` : ""} +
+ +
${this.textGetter(this.options[0])}
+ +
+
+ `; + } + + /** + * @param {HTMLElement} parent + * @param {Array} clickTrackers + */ + bindEvents(parent, clickTrackers) { + this.element = this.getFormElement(parent); + + const children = this.element.children; + for (let i = 0; i < children.length; ++i) { + const child = children[i]; + const detector = new ClickDetector(child, { preventDefault: false }); + clickTrackers.push(detector); + const change = child.classList.contains("prev") ? -1 : 1; + detector.click.add(() => this.toggle(change), this); + } + } + + getValue() { + return this.valueGetter(this.options[this.index]); + } + + toggle(amount) { + this.index = safeModulo(this.index + amount, this.options.length); + this.element.querySelector(".value").innerText = this.textGetter(this.options[this.index]); + } + + focus() {} +} diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index 31e90a4f..0057e03c 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -9,10 +9,38 @@ 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 { FormElementInput, FormElementCheckbox } from "../../../core/modal_dialog_forms"; +import { FormElementInput, FormElementCheckbox, FormElementEnum } from "../../../core/modal_dialog_forms"; const logger = createLogger("screenshot_exporter"); +/** + * @typedef {{mode: string, resolution?: number}} QualityOptions + */ + +/** + * @type {{id: string, options: QualityOptions}[]} + */ +const screenshotQualities = [ + { + id: "high", + options: { mode: "regular", resolution: 16384 }, + }, + { + id: "medium", + options: { mode: "regular", resolution: 4096 }, + }, + { + id: "low", + options: { mode: "regular", resolution: 1024 }, + }, + { + id: "map", + options: { mode: "map" }, + }, +]; +// @TODO: translation (T.dialogs.exportScreenshotWarning.qualities) +const qualityNames = { high: "High", medium: "Medium", low: "Low", map: "Map" }; + export class HUDScreenshotExporter extends BaseHUDPart { createElements() {} @@ -26,23 +54,24 @@ export class HUDScreenshotExporter extends BaseHUDPart { return; } + const qualityInput = new FormElementEnum({ + id: "screenshotQuality", + options: screenshotQualities, + valueGetter: quality => quality.options, + // @TODO: translation (T.dialogs.exportScreenshotWarning.qualityLabel) + textGetter: quality => "Quality:" + " " + qualityNames[quality.id], + }); const layerInput = new FormElementCheckbox({ id: "screenshotLayer", + // @TODO: translation (T.dialogs.exportScreenshotWarning.descLayer) label: "Include wires layer", defaultValue: this.root.currentLayer === "wires" ? true : false, }); - const qualityInput = new FormElementInput({ - id: "screenshotQuality", - label: "Pixel width per tile", - placeholder: "", - defaultValue: "", - validator: val => !isNaN(val) && parseInt(val) === parseFloat(val) && !isNaN(parseInt(val, 10)), - }); const dialog = new DialogWithForm({ app: this.root.app, title: T.dialogs.exportScreenshotWarning.title, desc: T.dialogs.exportScreenshotWarning.desc, - formElements: [layerInput, qualityInput], + formElements: [qualityInput, layerInput], buttons: ["cancel:good", "ok:bad"], }); @@ -53,7 +82,11 @@ export class HUDScreenshotExporter extends BaseHUDPart { ); } - doExport(wiresLayer, quality) { + /** + * @param {boolean} wiresLayer + * @param {QualityOptions} options + */ + doExport(wiresLayer, options) { logger.log("Starting export ..."); // Find extends @@ -76,12 +109,15 @@ export class HUDScreenshotExporter extends BaseHUDPart { const dimensions = maxChunk.sub(minChunk); logger.log("Dimensions:", dimensions); - let chunkSizePixels = quality * globalConfig.mapChunkSize; const maxDimensions = Math.max(dimensions.x, dimensions.y); - if (maxDimensions > 128) { - chunkSizePixels = Math.max(1, Math.floor(chunkSizePixels * (128 / maxDimensions))); - } + // we want integer pixels per tile + // if resolution too low, we want integer pixels per chunk + const chunkSizePixels = + maxDimensions * globalConfig.mapChunkSize > options.resolution + ? Math.max(1, Math.floor(options.resolution / maxDimensions)) + : Math.floor(options.resolution / (maxDimensions * globalConfig.mapChunkSize)) * + globalConfig.mapChunkSize; logger.log("ChunkSizePixels:", chunkSizePixels); const chunkScale = chunkSizePixels / globalConfig.mapChunkWorldSize; From 4ceb15051aaeaf0108c29901666e63b732a1cdb9 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Wed, 31 Mar 2021 18:15:50 -0500 Subject: [PATCH 03/24] Improve screenshot dialog and algorithm The CSS for checkbox and enum form elements is modified to make them fit better. Map mode is made a separate setting in the screenshot dialog, and the rendering process is made to match how it is done ingame. --- src/css/ingame_hud/dialogs.scss | 18 ++-- src/js/game/hud/parts/screenshot_exporter.js | 98 +++++++++++++------- src/js/game/hud/parts/wires_overlay.js | 7 +- 3 files changed, 79 insertions(+), 44 deletions(-) diff --git a/src/css/ingame_hud/dialogs.scss b/src/css/ingame_hud/dialogs.scss index 38e359e4..6d5500d4 100644 --- a/src/css/ingame_hud/dialogs.scss +++ b/src/css/ingame_hud/dialogs.scss @@ -215,24 +215,28 @@ } } - .checkBoxFormElem { + .checkBoxFormElem, + .enumFormElem { + display: flex; + align-items: center; @include S(margin, 10px, 0); + > label { @include S(margin-right, 10px); } - display: flex; - align-items: center; } .enum { - @include S(margin, 10px, 0); display: grid; grid-template-columns: auto 1fr auto; @include S(grid-gap, 4px); - @include S(width, 200px); + @include S(min-width, 160px); - > * { + > div { background: #fff; + display: flex; + justify-content: center; + align-items: center; text-align: center; pointer-events: all; cursor: pointer; @@ -253,7 +257,7 @@ } &.toggle { - @include S(width, 20px); + @include S(width, 16px); } &.value { diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index 0057e03c..7d91671b 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -9,37 +9,28 @@ 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 { FormElementInput, FormElementCheckbox, FormElementEnum } from "../../../core/modal_dialog_forms"; +import { FormElementCheckbox, FormElementEnum } from "../../../core/modal_dialog_forms"; +import { ORIGINAL_SPRITE_SCALE } from "../../../core/sprites"; +import { getDeviceDPI } from "../../../core/dpi_manager"; const logger = createLogger("screenshot_exporter"); -/** - * @typedef {{mode: string, resolution?: number}} QualityOptions - */ - -/** - * @type {{id: string, options: QualityOptions}[]} - */ const screenshotQualities = [ { id: "high", - options: { mode: "regular", resolution: 16384 }, + resolution: 16384, }, { id: "medium", - options: { mode: "regular", resolution: 4096 }, + resolution: 4096, }, { id: "low", - options: { mode: "regular", resolution: 1024 }, - }, - { - id: "map", - options: { mode: "map" }, + resolution: 1024, }, ]; // @TODO: translation (T.dialogs.exportScreenshotWarning.qualities) -const qualityNames = { high: "High", medium: "Medium", low: "Low", map: "Map" }; +const qualityNames = { high: "High", medium: "Medium", low: "Low" }; export class HUDScreenshotExporter extends BaseHUDPart { createElements() {} @@ -56,10 +47,17 @@ export class HUDScreenshotExporter extends BaseHUDPart { const qualityInput = new FormElementEnum({ id: "screenshotQuality", + label: "Quality", options: screenshotQualities, - valueGetter: quality => quality.options, + valueGetter: quality => quality.resolution, // @TODO: translation (T.dialogs.exportScreenshotWarning.qualityLabel) - textGetter: quality => "Quality:" + " " + qualityNames[quality.id], + textGetter: quality => qualityNames[quality.id], + }); + const overlayInput = new FormElementCheckbox({ + id: "screenshotView", + // @TODO: translation (T.dialogs.exportScreenshotWarning.descOverlay) + label: "Map view", + defaultValue: this.root.camera.getIsMapOverlayActive() ? true : false, }); const layerInput = new FormElementCheckbox({ id: "screenshotLayer", @@ -71,22 +69,24 @@ export class HUDScreenshotExporter extends BaseHUDPart { app: this.root.app, title: T.dialogs.exportScreenshotWarning.title, desc: T.dialogs.exportScreenshotWarning.desc, - formElements: [qualityInput, layerInput], + formElements: [qualityInput, overlayInput, layerInput], buttons: ["cancel:good", "ok:bad"], }); this.root.hud.parts.dialogs.internalShowDialog(dialog); dialog.buttonSignals.ok.add( - () => this.doExport(layerInput.getValue(), qualityInput.getValue()), + () => this.doExport(qualityInput.getValue(), overlayInput.getValue(), layerInput.getValue()), this ); } /** + * Renders a screenshot of the entire base as closely as possible to the ingame camera + * @param {number} resolution + * @param {boolean} overlay * @param {boolean} wiresLayer - * @param {QualityOptions} options */ - doExport(wiresLayer, options) { + doExport(resolution, overlay, wiresLayer) { logger.log("Starting export ..."); // Find extends @@ -114,15 +114,28 @@ export class HUDScreenshotExporter extends BaseHUDPart { // we want integer pixels per tile // if resolution too low, we want integer pixels per chunk const chunkSizePixels = - maxDimensions * globalConfig.mapChunkSize > options.resolution - ? Math.max(1, Math.floor(options.resolution / maxDimensions)) - : Math.floor(options.resolution / (maxDimensions * globalConfig.mapChunkSize)) * + maxDimensions * globalConfig.mapChunkSize > resolution + ? Math.max(1, Math.floor(resolution / maxDimensions)) + : Math.floor(resolution / (maxDimensions * globalConfig.mapChunkSize)) * globalConfig.mapChunkSize; logger.log("ChunkSizePixels:", chunkSizePixels); + // equivalent to zoomLevel const chunkScale = chunkSizePixels / globalConfig.mapChunkWorldSize; logger.log("Scale:", chunkScale); + // Compute atlas scale + const lowQuality = this.root.app.settings.getAllSettings().lowQualityTextures; + const effectiveZoomLevel = + (chunkScale / globalConfig.assetsDpi) * getDeviceDPI() * globalConfig.assetsSharpness; + + let desiredAtlasScale = "0.25"; + if (effectiveZoomLevel > 0.5 && !lowQuality) { + desiredAtlasScale = ORIGINAL_SPRITE_SCALE; + } else if (effectiveZoomLevel > 0.35 && !lowQuality) { + desiredAtlasScale = "0.5"; + } + logger.log("Allocating buffer, if the factory grew too big it will crash here"); const [canvas, context] = makeOffscreenBuffer( dimensions.x * chunkSizePixels, @@ -144,7 +157,7 @@ export class HUDScreenshotExporter extends BaseHUDPart { const parameters = new DrawParameters({ context, visibleRect, - desiredAtlasScale: 0.25, + desiredAtlasScale, root: this.root, zoomLevel: chunkScale, }); @@ -152,17 +165,36 @@ export class HUDScreenshotExporter extends BaseHUDPart { context.scale(chunkScale, chunkScale); context.translate(-visibleRect.x, -visibleRect.y); + // hack but works + const currentLayer = this.root.currentLayer; + const currentAlpha = this.root.hud.parts.wiresOverlay.currentAlpha; + if (wiresLayer) { + this.root.currentLayer = "wires"; + this.root.hud.parts.wiresOverlay.currentAlpha = 1; + } else { + this.root.currentLayer = "regular"; + this.root.hud.parts.wiresOverlay.currentAlpha = 0; + } + // Render all relevant chunks this.root.signals.gameFrameStarted.dispatch(); - this.root.map.drawBackground(parameters); - this.root.systemMgr.systems.belt.drawBeltItems(parameters); - this.root.map.drawForeground(parameters); - this.root.systemMgr.systems.hub.draw(parameters); - if (wiresLayer) { - this.root.hud.parts.wiresOverlay.draw(parameters, true); - this.root.map.drawWiresForegroundLayer(parameters); + if (overlay) { + this.root; + this.root.map.drawOverlay(parameters); + } 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); + this.root.hud.parts.wiresOverlay.draw(parameters); + if (this.root.currentLayer === "wires") { + this.root.map.drawWiresForegroundLayer(parameters); + } } + this.root.currentLayer = currentLayer; + this.root.hud.parts.wiresOverlay.currentAlpha = currentAlpha; + // Offer export logger.log("Rendered buffer, exporting ..."); const image = canvas.toDataURL("image/png"); diff --git a/src/js/game/hud/parts/wires_overlay.js b/src/js/game/hud/parts/wires_overlay.js index 7a9b645f..328d6689 100644 --- a/src/js/game/hud/parts/wires_overlay.js +++ b/src/js/game/hud/parts/wires_overlay.js @@ -114,10 +114,9 @@ export class HUDWiresOverlay extends BaseHUDPart { /** * * @param {DrawParameters} parameters - * @param {boolean=} forced */ - draw(parameters, forced = false) { - if (!forced && this.currentAlpha < 0.02) { + draw(parameters) { + if (this.currentAlpha < 0.02) { return; } @@ -128,7 +127,7 @@ export class HUDWiresOverlay extends BaseHUDPart { const bounds = parameters.visibleRect; - parameters.context.globalAlpha = forced ? 1 : this.currentAlpha; + parameters.context.globalAlpha = this.currentAlpha; const scaleFactor = 1 / wiresBackgroundDpi; parameters.context.globalCompositeOperation = "overlay"; From 3f01c131c3dbb3998756e1fd94715812fa147c5c Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Thu, 1 Apr 2021 14:56:04 -0500 Subject: [PATCH 04/24] Increase minimum screenshot scale The pixels-per-tile for screenshots must now be an odd integer of at least 3. A screenshot will not be made if the canvas size is too large, and an info dialog will be shown. An additional quality setting that uses the minimum scale is added. The resolutions are now calculated in terms of the maximum canvas dimensions. --- src/js/game/hud/parts/screenshot_exporter.js | 33 ++++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index 7d91671b..af18216e 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -15,22 +15,28 @@ import { getDeviceDPI } from "../../../core/dpi_manager"; const logger = createLogger("screenshot_exporter"); +const MAX_CANVAS_DIMS = 16384; + const screenshotQualities = [ { id: "high", - resolution: 16384, + resolution: MAX_CANVAS_DIMS, }, { id: "medium", - resolution: 4096, + resolution: MAX_CANVAS_DIMS / 4, }, { id: "low", - resolution: 1024, + resolution: MAX_CANVAS_DIMS / 16, + }, + { + id: "pixels", + resolution: 0, }, ]; // @TODO: translation (T.dialogs.exportScreenshotWarning.qualities) -const qualityNames = { high: "High", medium: "Medium", low: "Low" }; +const qualityNames = { high: "High", medium: "Medium", low: "Low", pixels: "Pixels" }; export class HUDScreenshotExporter extends BaseHUDPart { createElements() {} @@ -111,15 +117,22 @@ export class HUDScreenshotExporter extends BaseHUDPart { const maxDimensions = Math.max(dimensions.x, dimensions.y); - // we want integer pixels per tile - // if resolution too low, we want integer pixels per chunk + // we want odd integer pixels per tile, so that center of tile is rendered + // at least 3 pixels per tile, for bearable quality const chunkSizePixels = - maxDimensions * globalConfig.mapChunkSize > resolution - ? Math.max(1, Math.floor(resolution / maxDimensions)) - : Math.floor(resolution / (maxDimensions * globalConfig.mapChunkSize)) * - globalConfig.mapChunkSize; + Math.max( + 3, + Math.floor((resolution / (maxDimensions * globalConfig.mapChunkSize) + 1) / 2) * 2 - 1 + ) * globalConfig.mapChunkSize; logger.log("ChunkSizePixels:", chunkSizePixels); + if (chunkSizePixels * maxDimensions > MAX_CANVAS_DIMS) { + logger.error("Maximum canvas size exceeded, aborting"); + //@TODO: translation (T.dialogs.exportScreenshotFail.title) (T.dialogs.exportScreenshotFail.text) + this.root.hud.parts.dialogs.showInfo("Too large", "The base is too large to render, sorry!"); + return; + } + // equivalent to zoomLevel const chunkScale = chunkSizePixels / globalConfig.mapChunkWorldSize; logger.log("Scale:", chunkScale); From 3eddf88fd34034fb472c9e56fe449af9a644c791 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Tue, 1 Jun 2021 18:38:31 -0500 Subject: [PATCH 05/24] Allow for closing screenshot dialog with same key --- src/js/game/hud/parts/screenshot_exporter.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index af18216e..5556fddb 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -79,6 +79,12 @@ export class HUDScreenshotExporter extends BaseHUDPart { buttons: ["cancel:good", "ok:bad"], }); + dialog.inputReciever.keydown.add(({ keyCode }) => { + if (keyCode === KEYMAPPINGS.ingame.exportScreenshot.keyCode) { + this.root.hud.parts.dialogs.closeDialog(dialog); + } + }); + this.root.hud.parts.dialogs.internalShowDialog(dialog); dialog.buttonSignals.ok.add( () => this.doExport(qualityInput.getValue(), overlayInput.getValue(), layerInput.getValue()), From 86ce48ab2a55cea862db669c2a3c6a158c9b69ac Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Tue, 1 Jun 2021 20:55:31 -0500 Subject: [PATCH 06/24] add screenshot from selected area --- src/js/game/hud/parts/screenshot_exporter.js | 90 +++++++++++++------- 1 file changed, 58 insertions(+), 32 deletions(-) diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index 5556fddb..d819890f 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -12,6 +12,7 @@ import { DialogWithForm } from "../../../core/modal_dialog_elements"; import { FormElementCheckbox, FormElementEnum } from "../../../core/modal_dialog_forms"; import { ORIGINAL_SPRITE_SCALE } from "../../../core/sprites"; import { getDeviceDPI } from "../../../core/dpi_manager"; +import { HUDMassSelector } from "./mass_selector"; const logger = createLogger("screenshot_exporter"); @@ -51,6 +52,18 @@ export class HUDScreenshotExporter extends BaseHUDPart { return; } + let bounds = undefined; + const massSelector = this.root.hud.parts.massSelector; + if (massSelector instanceof HUDMassSelector && massSelector.currentSelectionStartWorld) { + const worldStart = massSelector.currentSelectionStartWorld; + const worldEnd = this.root.camera.screenToWorld(massSelector.currentSelectionEnd); + + const tileStart = worldStart.toTileSpace(); + const tileEnd = worldEnd.toTileSpace(); + + bounds = Rectangle.fromTwoPoints(tileStart, tileEnd.addScalars(1, 1)); + } + const qualityInput = new FormElementEnum({ id: "screenshotQuality", label: "Quality", @@ -87,7 +100,13 @@ export class HUDScreenshotExporter extends BaseHUDPart { this.root.hud.parts.dialogs.internalShowDialog(dialog); dialog.buttonSignals.ok.add( - () => this.doExport(qualityInput.getValue(), overlayInput.getValue(), layerInput.getValue()), + () => + this.doExport( + qualityInput.getValue(), + overlayInput.getValue(), + layerInput.getValue(), + bounds + ), this ); } @@ -97,8 +116,9 @@ export class HUDScreenshotExporter extends BaseHUDPart { * @param {number} resolution * @param {boolean} overlay * @param {boolean} wiresLayer + * @param {Rectangle?} bounds */ - doExport(resolution, overlay, wiresLayer) { + doExport(resolution, overlay, wiresLayer, bounds) { logger.log("Starting export ..."); // Find extends @@ -106,47 +126,53 @@ export class HUDScreenshotExporter extends BaseHUDPart { const minTile = new Vector(0, 0); const maxTile = new Vector(0, 0); - for (let i = 0; i < staticEntities.length; ++i) { - const bounds = staticEntities[i].components.StaticMapEntity.getTileSpaceBounds(); - minTile.x = Math.min(minTile.x, bounds.x); - minTile.y = Math.min(minTile.y, bounds.y); + if (bounds) { + minTile.x = bounds.x; + minTile.y = bounds.y; - maxTile.x = Math.max(maxTile.x, bounds.x + bounds.w); - maxTile.y = Math.max(maxTile.y, bounds.y + bounds.h); + maxTile.x = bounds.x + bounds.w; + maxTile.y = bounds.y + bounds.h; + } else { + for (let i = 0; i < staticEntities.length; ++i) { + const entityBounds = staticEntities[i].components.StaticMapEntity.getTileSpaceBounds(); + minTile.x = Math.min(minTile.x, entityBounds.x); + minTile.y = Math.min(minTile.y, entityBounds.y); + + maxTile.x = Math.max(maxTile.x, entityBounds.x + entityBounds.w); + maxTile.y = Math.max(maxTile.y, entityBounds.y + entityBounds.h); + } + + minTile.x = Math.floor(minTile.x / globalConfig.mapChunkSize) * globalConfig.mapChunkSize; + minTile.y = Math.floor(minTile.y / globalConfig.mapChunkSize) * globalConfig.mapChunkSize; + + maxTile.x = Math.ceil(maxTile.x / globalConfig.mapChunkSize) * globalConfig.mapChunkSize; + maxTile.y = Math.ceil(maxTile.y / globalConfig.mapChunkSize) * globalConfig.mapChunkSize; } - const minChunk = minTile.divideScalar(globalConfig.mapChunkSize).floor(); - const maxChunk = maxTile.divideScalar(globalConfig.mapChunkSize).ceil(); - - const dimensions = maxChunk.sub(minChunk); + const dimensions = maxTile.sub(minTile); logger.log("Dimensions:", dimensions); const maxDimensions = Math.max(dimensions.x, dimensions.y); // we want odd integer pixels per tile, so that center of tile is rendered // at least 3 pixels per tile, for bearable quality - const chunkSizePixels = - Math.max( - 3, - Math.floor((resolution / (maxDimensions * globalConfig.mapChunkSize) + 1) / 2) * 2 - 1 - ) * globalConfig.mapChunkSize; - logger.log("ChunkSizePixels:", chunkSizePixels); + const tileSizePixels = Math.max(3, Math.floor((resolution / maxDimensions + 1) / 2) * 2 - 1); + logger.log("ChunkSizePixels:", tileSizePixels); - if (chunkSizePixels * maxDimensions > MAX_CANVAS_DIMS) { + if (tileSizePixels * maxDimensions > MAX_CANVAS_DIMS) { logger.error("Maximum canvas size exceeded, aborting"); - //@TODO: translation (T.dialogs.exportScreenshotFail.title) (T.dialogs.exportScreenshotFail.text) + // @TODO: translation (T.dialogs.exportScreenshotFail.title) (T.dialogs.exportScreenshotFail.text) this.root.hud.parts.dialogs.showInfo("Too large", "The base is too large to render, sorry!"); return; } - // equivalent to zoomLevel - const chunkScale = chunkSizePixels / globalConfig.mapChunkWorldSize; - logger.log("Scale:", chunkScale); + const zoomLevel = tileSizePixels / globalConfig.tileSize; + logger.log("Scale:", zoomLevel); // Compute atlas scale const lowQuality = this.root.app.settings.getAllSettings().lowQualityTextures; const effectiveZoomLevel = - (chunkScale / globalConfig.assetsDpi) * getDeviceDPI() * globalConfig.assetsSharpness; + (zoomLevel / globalConfig.assetsDpi) * getDeviceDPI() * globalConfig.assetsSharpness; let desiredAtlasScale = "0.25"; if (effectiveZoomLevel > 0.5 && !lowQuality) { @@ -157,8 +183,8 @@ export class HUDScreenshotExporter extends BaseHUDPart { logger.log("Allocating buffer, if the factory grew too big it will crash here"); const [canvas, context] = makeOffscreenBuffer( - dimensions.x * chunkSizePixels, - dimensions.y * chunkSizePixels, + dimensions.x * tileSizePixels, + dimensions.y * tileSizePixels, { smooth: true, reusable: false, @@ -168,20 +194,20 @@ export class HUDScreenshotExporter extends BaseHUDPart { logger.log("Got buffer, rendering now ..."); const visibleRect = new Rectangle( - minChunk.x * globalConfig.mapChunkWorldSize, - minChunk.y * globalConfig.mapChunkWorldSize, - dimensions.x * globalConfig.mapChunkWorldSize, - dimensions.y * globalConfig.mapChunkWorldSize + minTile.x * globalConfig.tileSize, + minTile.y * globalConfig.tileSize, + dimensions.x * globalConfig.tileSize, + dimensions.y * globalConfig.tileSize ); const parameters = new DrawParameters({ context, visibleRect, desiredAtlasScale, root: this.root, - zoomLevel: chunkScale, + zoomLevel: zoomLevel, }); - context.scale(chunkScale, chunkScale); + context.scale(zoomLevel, zoomLevel); context.translate(-visibleRect.x, -visibleRect.y); // hack but works From 7a1e7fac921864c4aea3d7eeda3008e0997634ed Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Tue, 1 Jun 2021 23:11:26 -0500 Subject: [PATCH 07/24] add screenshot from selected buildings --- src/js/game/hud/parts/screenshot_exporter.js | 32 ++++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index d819890f..be179c81 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -54,14 +54,34 @@ export class HUDScreenshotExporter extends BaseHUDPart { let bounds = undefined; const massSelector = this.root.hud.parts.massSelector; - if (massSelector instanceof HUDMassSelector && massSelector.currentSelectionStartWorld) { - const worldStart = massSelector.currentSelectionStartWorld; - const worldEnd = this.root.camera.screenToWorld(massSelector.currentSelectionEnd); + if (massSelector instanceof HUDMassSelector) { + if (massSelector.currentSelectionStartWorld) { + const worldStart = massSelector.currentSelectionStartWorld; + const worldEnd = this.root.camera.screenToWorld(massSelector.currentSelectionEnd); - const tileStart = worldStart.toTileSpace(); - const tileEnd = worldEnd.toTileSpace(); + const tileStart = worldStart.toTileSpace(); + const tileEnd = worldEnd.toTileSpace(); - bounds = Rectangle.fromTwoPoints(tileStart, tileEnd.addScalars(1, 1)); + bounds = Rectangle.fromTwoPoints(tileStart, tileEnd.addScalars(1, 1)); + } else if (massSelector.selectedUids.size > 0) { + const minTile = new Vector(Infinity, Infinity); + const maxTile = new Vector(-Infinity, -Infinity); + + const entityUids = Array.from(massSelector.selectedUids); + for (let i = 0; i < entityUids.length; ++i) { + const entityBounds = this.root.entityMgr + .findByUid(entityUids[i]) + .components.StaticMapEntity.getTileSpaceBounds(); + + minTile.x = Math.min(minTile.x, entityBounds.x); + minTile.y = Math.min(minTile.y, entityBounds.y); + + maxTile.x = Math.max(maxTile.x, entityBounds.x + entityBounds.w); + maxTile.y = Math.max(maxTile.y, entityBounds.y + entityBounds.h); + } + + bounds = Rectangle.fromTwoPoints(minTile, maxTile); + } } const qualityInput = new FormElementEnum({ From 470beeadb1108b4c5585e7bd9709676583e660cf Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Wed, 2 Jun 2021 23:03:42 -0500 Subject: [PATCH 08/24] change pixels per tile calculation --- src/js/game/hud/parts/screenshot_exporter.js | 25 +++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index be179c81..d9d82ea5 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -13,6 +13,7 @@ import { FormElementCheckbox, FormElementEnum } from "../../../core/modal_dialog import { ORIGINAL_SPRITE_SCALE } from "../../../core/sprites"; import { getDeviceDPI } from "../../../core/dpi_manager"; import { HUDMassSelector } from "./mass_selector"; +import { clamp } from "../../../core/utils"; const logger = createLogger("screenshot_exporter"); @@ -174,10 +175,23 @@ export class HUDScreenshotExporter extends BaseHUDPart { const maxDimensions = Math.max(dimensions.x, dimensions.y); - // we want odd integer pixels per tile, so that center of tile is rendered - // at least 3 pixels per tile, for bearable quality - const tileSizePixels = Math.max(3, Math.floor((resolution / maxDimensions + 1) / 2) * 2 - 1); - logger.log("ChunkSizePixels:", tileSizePixels); + const tileSizePixels = overlay + ? // we want multiple of 3 pixels per tile, since the map mode buildings are 3x3 pixels + // higher resolutions are to render resource patch icons + clamp( + Math.floor(resolution / maxDimensions / 3) * 3, + 3, + Math.floor((globalConfig.assetsDpi * globalConfig.tileSize) / 3) * 3 + ) + : // we want odd integer pixels per tile, so that center of tile is rendered + // at least 3 pixels per tile, for bearable quality + // at most the resolution of the assets, to not be excessive + clamp( + Math.floor((resolution / maxDimensions + 1) / 2) * 2 - 1, + 3, + globalConfig.assetsDpi * globalConfig.tileSize + ); + logger.log("Pixels per tile:", tileSizePixels); if (tileSizePixels * maxDimensions > MAX_CANVAS_DIMS) { logger.error("Maximum canvas size exceeded, aborting"); @@ -191,8 +205,7 @@ export class HUDScreenshotExporter extends BaseHUDPart { // Compute atlas scale const lowQuality = this.root.app.settings.getAllSettings().lowQualityTextures; - const effectiveZoomLevel = - (zoomLevel / globalConfig.assetsDpi) * getDeviceDPI() * globalConfig.assetsSharpness; + const effectiveZoomLevel = (zoomLevel / globalConfig.assetsDpi) * globalConfig.assetsSharpness; let desiredAtlasScale = "0.25"; if (effectiveZoomLevel > 0.5 && !lowQuality) { From e92c0111b49edd7d6b839e73fce39954bea704f4 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Wed, 2 Jun 2021 23:32:03 -0500 Subject: [PATCH 09/24] use rectangle instead of two vectors --- src/js/game/hud/parts/screenshot_exporter.js | 39 +++++++------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index d9d82ea5..16af2535 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -145,15 +145,10 @@ export class HUDScreenshotExporter extends BaseHUDPart { // Find extends const staticEntities = this.root.entityMgr.getAllWithComponent(StaticMapEntityComponent); - const minTile = new Vector(0, 0); - const maxTile = new Vector(0, 0); - if (bounds) { - minTile.x = bounds.x; - minTile.y = bounds.y; + if (!bounds) { + const minTile = new Vector(0, 0); + const maxTile = new Vector(0, 0); - maxTile.x = bounds.x + bounds.w; - maxTile.y = bounds.y + bounds.h; - } else { for (let i = 0; i < staticEntities.length; ++i) { const entityBounds = staticEntities[i].components.StaticMapEntity.getTileSpaceBounds(); minTile.x = Math.min(minTile.x, entityBounds.x); @@ -168,12 +163,13 @@ export class HUDScreenshotExporter extends BaseHUDPart { maxTile.x = Math.ceil(maxTile.x / globalConfig.mapChunkSize) * globalConfig.mapChunkSize; maxTile.y = Math.ceil(maxTile.y / globalConfig.mapChunkSize) * globalConfig.mapChunkSize; + + bounds = Rectangle.fromTwoPoints(minTile, maxTile); } - const dimensions = maxTile.sub(minTile); - logger.log("Dimensions:", dimensions); + logger.log("Bounds:", bounds); - const maxDimensions = Math.max(dimensions.x, dimensions.y); + const maxDimensions = Math.max(bounds.w, bounds.h); const tileSizePixels = overlay ? // we want multiple of 3 pixels per tile, since the map mode buildings are 3x3 pixels @@ -215,23 +211,14 @@ export class HUDScreenshotExporter extends BaseHUDPart { } logger.log("Allocating buffer, if the factory grew too big it will crash here"); - const [canvas, context] = makeOffscreenBuffer( - dimensions.x * tileSizePixels, - dimensions.y * tileSizePixels, - { - smooth: true, - reusable: false, - label: "export-buffer", - } - ); + const [canvas, context] = makeOffscreenBuffer(bounds.w * tileSizePixels, bounds.h * tileSizePixels, { + smooth: true, + reusable: false, + label: "export-buffer", + }); logger.log("Got buffer, rendering now ..."); - const visibleRect = new Rectangle( - minTile.x * globalConfig.tileSize, - minTile.y * globalConfig.tileSize, - dimensions.x * globalConfig.tileSize, - dimensions.y * globalConfig.tileSize - ); + const visibleRect = bounds.allScaled(globalConfig.tileSize); const parameters = new DrawParameters({ context, visibleRect, From 3f9229dc7cefed8b5a2e2b56f0db2d97423d716f Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Thu, 3 Jun 2021 13:05:56 -0500 Subject: [PATCH 10/24] move staticEntities to relevant scope --- src/js/game/hud/parts/screenshot_exporter.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index 16af2535..d4c03beb 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -142,13 +142,12 @@ export class HUDScreenshotExporter extends BaseHUDPart { doExport(resolution, overlay, wiresLayer, bounds) { logger.log("Starting export ..."); - // Find extends - const staticEntities = this.root.entityMgr.getAllWithComponent(StaticMapEntityComponent); - if (!bounds) { + // Find extends + const staticEntities = this.root.entityMgr.getAllWithComponent(StaticMapEntityComponent); + const minTile = new Vector(0, 0); const maxTile = new Vector(0, 0); - for (let i = 0; i < staticEntities.length; ++i) { const entityBounds = staticEntities[i].components.StaticMapEntity.getTileSpaceBounds(); minTile.x = Math.min(minTile.x, entityBounds.x); From 84c2aee7dadf77ec04119be357b88a253bb6c2a0 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Fri, 4 Jun 2021 12:49:34 -0500 Subject: [PATCH 11/24] allow for border around selected area --- src/js/game/hud/parts/screenshot_exporter.js | 72 +++++++++++++------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index d4c03beb..247655c1 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -14,10 +14,14 @@ 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"; const logger = createLogger("screenshot_exporter"); const MAX_CANVAS_DIMS = 16384; +// should be odd so that the centers of tiles are rendered +// as pixels per tile must be a multiple of this +const TARGET_INVERSE_BORDER = 3; const screenshotQualities = [ { @@ -126,6 +130,7 @@ export class HUDScreenshotExporter extends BaseHUDPart { qualityInput.getValue(), overlayInput.getValue(), layerInput.getValue(), + !!bounds, bounds ), this @@ -134,15 +139,16 @@ export class HUDScreenshotExporter extends BaseHUDPart { /** * Renders a screenshot of the entire base as closely as possible to the ingame camera - * @param {number} resolution + * @param {number} targetResolution * @param {boolean} overlay * @param {boolean} wiresLayer - * @param {Rectangle?} bounds + * @param {boolean} allowBorder + * @param {Rectangle?} tileBounds */ - doExport(resolution, overlay, wiresLayer, bounds) { + doExport(targetResolution, overlay, wiresLayer, allowBorder, tileBounds) { logger.log("Starting export ..."); - if (!bounds) { + if (!tileBounds) { // Find extends const staticEntities = this.root.entityMgr.getAllWithComponent(StaticMapEntityComponent); @@ -163,32 +169,42 @@ export class HUDScreenshotExporter extends BaseHUDPart { maxTile.x = Math.ceil(maxTile.x / globalConfig.mapChunkSize) * globalConfig.mapChunkSize; maxTile.y = Math.ceil(maxTile.y / globalConfig.mapChunkSize) * globalConfig.mapChunkSize; - bounds = Rectangle.fromTwoPoints(minTile, maxTile); + tileBounds = Rectangle.fromTwoPoints(minTile, maxTile); } + // if the desired pixels per tile is too small, we do not create a border + // so that we have more valid values for pixels per tile + // we do not create a border for map view since there is no sprite overflow + const border = + allowBorder && + !overlay && + targetResolution / (Math.max(tileBounds.w, tileBounds.h) + 2 / TARGET_INVERSE_BORDER) >= + 3 * TARGET_INVERSE_BORDER; + + const bounds = border ? tileBounds.expandedInAllDirections(1 / TARGET_INVERSE_BORDER) : tileBounds; logger.log("Bounds:", bounds); const maxDimensions = Math.max(bounds.w, bounds.h); + // at least 3 pixels per tile, for bearable quality + // at most the resolution of the assets, to not be excessive + const clamped = clamp( + targetResolution / (maxDimensions + (border ? 2 / 3 : 0)), + 3, + globalConfig.assetsDpi * globalConfig.tileSize + ); + + // 1 is a fake value since it behaves the same as a border width of 0 + const inverseBorder = border ? TARGET_INVERSE_BORDER : 1; const tileSizePixels = overlay - ? // we want multiple of 3 pixels per tile, since the map mode buildings are 3x3 pixels - // higher resolutions are to render resource patch icons - clamp( - Math.floor(resolution / maxDimensions / 3) * 3, - 3, - Math.floor((globalConfig.assetsDpi * globalConfig.tileSize) / 3) * 3 - ) - : // we want odd integer pixels per tile, so that center of tile is rendered - // at least 3 pixels per tile, for bearable quality - // at most the resolution of the assets, to not be excessive - clamp( - Math.floor((resolution / maxDimensions + 1) / 2) * 2 - 1, - 3, - globalConfig.assetsDpi * globalConfig.tileSize - ); + ? // we floor to the nearest multiple of the map view tile resolution + Math.floor(clamped / CHUNK_OVERLAY_RES) * CHUNK_OVERLAY_RES || CHUNK_OVERLAY_RES + : // we floor to the nearest odd multiple so that the center of each building is rendered + Math.floor((clamped + inverseBorder) / (2 * inverseBorder)) * (2 * inverseBorder) - + inverseBorder || inverseBorder; logger.log("Pixels per tile:", tileSizePixels); - if (tileSizePixels * maxDimensions > MAX_CANVAS_DIMS) { + if (Math.round(tileSizePixels * maxDimensions) > MAX_CANVAS_DIMS) { logger.error("Maximum canvas size exceeded, aborting"); // @TODO: translation (T.dialogs.exportScreenshotFail.title) (T.dialogs.exportScreenshotFail.text) this.root.hud.parts.dialogs.showInfo("Too large", "The base is too large to render, sorry!"); @@ -210,11 +226,15 @@ export class HUDScreenshotExporter extends BaseHUDPart { } logger.log("Allocating buffer, if the factory grew too big it will crash here"); - const [canvas, context] = makeOffscreenBuffer(bounds.w * tileSizePixels, bounds.h * tileSizePixels, { - smooth: true, - reusable: false, - label: "export-buffer", - }); + const [canvas, context] = makeOffscreenBuffer( + Math.round(bounds.w * tileSizePixels), + Math.round(bounds.h * tileSizePixels), + { + smooth: true, + reusable: false, + label: "export-buffer", + } + ); logger.log("Got buffer, rendering now ..."); const visibleRect = bounds.allScaled(globalConfig.tileSize); From 2ad07f9ace395cf86342e722b0bb7552630d2195 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Fri, 4 Jun 2021 12:52:13 -0500 Subject: [PATCH 12/24] fix incorrect bounds with selection --- src/js/game/hud/parts/screenshot_exporter.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index 247655c1..b5b6c4b0 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -67,7 +67,9 @@ export class HUDScreenshotExporter extends BaseHUDPart { const tileStart = worldStart.toTileSpace(); const tileEnd = worldEnd.toTileSpace(); - bounds = Rectangle.fromTwoPoints(tileStart, tileEnd.addScalars(1, 1)); + bounds = Rectangle.fromTwoPoints(tileStart, tileEnd); + bounds.w += 1; + bounds.h += 1; } else if (massSelector.selectedUids.size > 0) { const minTile = new Vector(Infinity, Infinity); const maxTile = new Vector(-Infinity, -Infinity); From a806708333ad1e3d87f31d1c8db505df8b9dd8a6 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Fri, 4 Jun 2021 13:47:53 -0500 Subject: [PATCH 13/24] add border to full base screenshot --- src/js/game/hud/parts/screenshot_exporter.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index b5b6c4b0..bff77459 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -171,7 +171,9 @@ export class HUDScreenshotExporter extends BaseHUDPart { maxTile.x = Math.ceil(maxTile.x / globalConfig.mapChunkSize) * globalConfig.mapChunkSize; maxTile.y = Math.ceil(maxTile.y / globalConfig.mapChunkSize) * globalConfig.mapChunkSize; - tileBounds = Rectangle.fromTwoPoints(minTile, maxTile); + tileBounds = Rectangle.fromTwoPoints(minTile, maxTile).expandedInAllDirections( + globalConfig.mapChunkSize + ); } // if the desired pixels per tile is too small, we do not create a border From 0dae172037ad0485549ca0e87362ea3c2449ebd7 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Fri, 4 Jun 2021 15:04:21 -0500 Subject: [PATCH 14/24] improve dialog text --- src/js/game/hud/parts/screenshot_exporter.js | 35 +++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index bff77459..1bf8f4d5 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -57,6 +57,7 @@ export class HUDScreenshotExporter extends BaseHUDPart { return; } + /** @type {Rectangle} */ let bounds = undefined; const massSelector = this.root.hud.parts.massSelector; if (massSelector instanceof HUDMassSelector) { @@ -108,13 +109,24 @@ export class HUDScreenshotExporter extends BaseHUDPart { const layerInput = new FormElementCheckbox({ id: "screenshotLayer", // @TODO: translation (T.dialogs.exportScreenshotWarning.descLayer) - label: "Include wires layer", + label: "Wires layer", defaultValue: this.root.currentLayer === "wires" ? true : false, }); const dialog = new DialogWithForm({ app: this.root.app, title: T.dialogs.exportScreenshotWarning.title, - desc: T.dialogs.exportScreenshotWarning.desc, + desc: bounds + ? // @TODO: translation (T.dialogs.exportScreenshotWarning.descSelection) + "You requested to export a region of your base as a screenshot. Please note that this will be quite slow for a bigger region and could potentially crash your game!" + : // @TODO: update translation (T.dialogs.exportScreenshotWarning.desc) + "You requested to export your base as a screenshot. Please note that this will be quite slow for a bigger base and could potentially crash your game!

Tip: You can select a region with to only take a screenshot of that region.".replace( + "", + "" + + this.root.keyMapper + .getBinding(KEYMAPPINGS.massSelect.massSelectStart) + .getKeyCodeString() + + "" + ), formElements: [qualityInput, overlayInput, layerInput], buttons: ["cancel:good", "ok:bad"], }); @@ -150,6 +162,7 @@ export class HUDScreenshotExporter extends BaseHUDPart { doExport(targetResolution, overlay, wiresLayer, allowBorder, tileBounds) { logger.log("Starting export ..."); + const boundsSelected = !!tileBounds; if (!tileBounds) { // Find extends const staticEntities = this.root.entityMgr.getAllWithComponent(StaticMapEntityComponent); @@ -210,8 +223,22 @@ export class HUDScreenshotExporter extends BaseHUDPart { if (Math.round(tileSizePixels * maxDimensions) > MAX_CANVAS_DIMS) { logger.error("Maximum canvas size exceeded, aborting"); - // @TODO: translation (T.dialogs.exportScreenshotFail.title) (T.dialogs.exportScreenshotFail.text) - this.root.hud.parts.dialogs.showInfo("Too large", "The base is too large to render, sorry!"); + this.root.hud.parts.dialogs.showInfo( + // @TODO: translation (T.dialogs.exportScreenshotFail.title) + "Too large", + boundsSelected + ? // @TODO: translation (T.dialogs.exportScreenshotFail.descSelection) + "The region selected is too large to render, sorry! Try selecting a smaller region." + : // @TODO: translation (T.dialogs.exportScreenshotFail.desc) + "The base is too large to render, sorry! Try selecting just a region of your base with .".replace( + "", + "" + + this.root.keyMapper + .getBinding(KEYMAPPINGS.massSelect.massSelectStart) + .getKeyCodeString() + + "" + ) + ); return; } From cc2d3f9803655b6b709ebe98dbe5685b9a5a1212 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Fri, 4 Jun 2021 15:22:31 -0500 Subject: [PATCH 15/24] change default value of enum option --- src/js/core/modal_dialog_forms.js | 6 +++--- src/js/game/hud/parts/screenshot_exporter.js | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/js/core/modal_dialog_forms.js b/src/js/core/modal_dialog_forms.js index 9242c57e..2f2401a9 100644 --- a/src/js/core/modal_dialog_forms.js +++ b/src/js/core/modal_dialog_forms.js @@ -238,12 +238,12 @@ export class FormElementItemChooser extends FormElement { } export class FormElementEnum extends FormElement { - constructor({ id, label = null, options, valueGetter, textGetter }) { + constructor({ id, label = null, options, defaultValue = 0, valueGetter, textGetter }) { super(id, label); this.options = options; this.valueGetter = valueGetter; this.textGetter = textGetter; - this.index = 0; + this.index = defaultValue; this.element = null; } @@ -254,7 +254,7 @@ export class FormElementEnum extends FormElement { ${this.label ? `` : ""}
-
${this.textGetter(this.options[0])}
+
${this.textGetter(this.options[this.index])}
diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index 1bf8f4d5..673dc9cd 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -96,6 +96,7 @@ export class HUDScreenshotExporter extends BaseHUDPart { id: "screenshotQuality", label: "Quality", options: screenshotQualities, + defaultValue: 1, valueGetter: quality => quality.resolution, // @TODO: translation (T.dialogs.exportScreenshotWarning.qualityLabel) textGetter: quality => qualityNames[quality.id], From 9c2fdcf09a030c8eb24b79f6835f5d899b527b51 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Fri, 4 Jun 2021 15:40:58 -0500 Subject: [PATCH 16/24] make keybindings in dialogs smaller --- src/css/ingame_hud/dialogs.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/css/ingame_hud/dialogs.scss b/src/css/ingame_hud/dialogs.scss index 6d5500d4..99dcc538 100644 --- a/src/css/ingame_hud/dialogs.scss +++ b/src/css/ingame_hud/dialogs.scss @@ -164,7 +164,7 @@ .keybinding { position: relative; background: #eee; - @include PlainText; + @include SuperSmallText; height: unset; margin: 1px 0; } From 1dae08552b53a2ea28bdb1b4b561c1c073cd82a2 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Fri, 4 Jun 2021 15:57:48 -0500 Subject: [PATCH 17/24] fix light mode enum color --- src/css/ingame_hud/dialogs.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/css/ingame_hud/dialogs.scss b/src/css/ingame_hud/dialogs.scss index 99dcc538..35d9aeb0 100644 --- a/src/css/ingame_hud/dialogs.scss +++ b/src/css/ingame_hud/dialogs.scss @@ -233,7 +233,7 @@ @include S(min-width, 160px); > div { - background: #fff; + background: $mainBgColor; display: flex; justify-content: center; align-items: center; @@ -245,7 +245,7 @@ transition: background-color 0.12s ease-in-out; &:hover { - background-color: #fafafa; + background-color: darken($mainBgColor, 5); } @include DarkThemeOverride { From 50f22ab5decc1c309a691dc5c4bbd0e70b9c0592 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Fri, 4 Jun 2021 18:19:25 -0500 Subject: [PATCH 18/24] align checkboxes, add transparent background --- src/css/ingame_hud/dialogs.scss | 12 ++ src/js/core/modal_dialog_forms.js | 27 +++- src/js/game/hud/parts/screenshot_exporter.js | 42 ++++++- src/js/game/map_chunk_view.js | 122 +++++++++++++++++++ 4 files changed, 196 insertions(+), 7 deletions(-) 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 From 86cef32bc2200c9b7e6237703416a0efb93d7c97 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Fri, 4 Jun 2021 19:02:40 -0500 Subject: [PATCH 19/24] change enum default to use id --- src/js/core/modal_dialog_forms.js | 15 +++++++++++++-- src/js/game/hud/parts/screenshot_exporter.js | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/js/core/modal_dialog_forms.js b/src/js/core/modal_dialog_forms.js index b27204f3..06bdafac 100644 --- a/src/js/core/modal_dialog_forms.js +++ b/src/js/core/modal_dialog_forms.js @@ -1,5 +1,6 @@ import { BaseItem } from "../game/base_item"; import { ClickDetector } from "./click_detector"; +import { createLogger } from "./logging"; import { Signal } from "./signal"; import { safeModulo } from "./utils"; @@ -14,6 +15,8 @@ import { safeModulo } from "./utils"; * *************************************************** */ +const logger = createLogger("dialog_forms"); + export class FormElement { constructor(id, label) { this.id = id; @@ -263,12 +266,20 @@ export class FormElementItemChooser extends FormElement { } export class FormElementEnum extends FormElement { - constructor({ id, label = null, options, defaultValue = 0, valueGetter, textGetter }) { + constructor({ id, label = null, options, defaultValue = null, valueGetter, textGetter }) { super(id, label); this.options = options; this.valueGetter = valueGetter; this.textGetter = textGetter; - this.index = defaultValue; + this.index = 0; + if (defaultValue !== null) { + const index = this.options.findIndex(option => option.id === defaultValue); + if (index >= 0) { + this.index = index; + } else { + logger.warn("Option ID", defaultValue, "not found in", options, "!"); + } + } this.element = null; } diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index 0ec46069..615d552c 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -100,7 +100,7 @@ export class HUDScreenshotExporter extends BaseHUDPart { id: "screenshotQuality", label: "Quality", options: screenshotQualities, - defaultValue: 1, + defaultValue: "medium", valueGetter: quality => quality.resolution, // @TODO: translation (T.dialogs.exportScreenshotWarning.qualityLabel) textGetter: quality => qualityNames[quality.id], From fc3b6eeb0c5ef1f55618c23d8b5d07adc33b1d6e Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Fri, 4 Jun 2021 19:15:28 -0500 Subject: [PATCH 20/24] move drawing belts to own function --- src/js/game/hud/parts/screenshot_exporter.js | 5 +---- src/js/game/map_chunk_view.js | 11 +++++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index 615d552c..139e98ef 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -321,10 +321,7 @@ export class HUDScreenshotExporter extends BaseHUDPart { 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); - } + MapChunkView.prototype.drawBackgroundLayerBeltsOnly ); } else { this.root.map.drawBackground(parameters); diff --git a/src/js/game/map_chunk_view.js b/src/js/game/map_chunk_view.js index cc5c43d9..66593fd3 100644 --- a/src/js/game/map_chunk_view.js +++ b/src/js/game/map_chunk_view.js @@ -53,6 +53,17 @@ export class MapChunkView extends MapChunk { systems.belt.drawChunk(parameters, this); } + /** + * Draws only the belts of the background layer + * @param {DrawParameters} parameters + */ + drawBackgroundLayerBeltsOnly(parameters) { + const systems = this.root.systemMgr.systems; + + systems.beltUnderlays.drawChunk(parameters, this); + systems.belt.drawChunk(parameters, this); + } + /** * Draws the dynamic foreground layer * @param {DrawParameters} parameters From ec02dcd07adfca3f993958f80a3552a73e346472 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Fri, 4 Jun 2021 20:10:24 -0500 Subject: [PATCH 21/24] fix item acceptor rendering from map view --- src/js/game/hud/parts/screenshot_exporter.js | 1 + src/js/game/systems/item_acceptor.js | 30 ++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index 139e98ef..96841846 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -307,6 +307,7 @@ export class HUDScreenshotExporter extends BaseHUDPart { this.root.currentLayer = "regular"; this.root.hud.parts.wiresOverlay.currentAlpha = 0; } + this.root.systemMgr.systems.itemAcceptor.updateForScreenshot(); // Render all relevant chunks this.root.signals.gameFrameStarted.dispatch(); diff --git a/src/js/game/systems/item_acceptor.js b/src/js/game/systems/item_acceptor.js index 780b4abd..ff95e21a 100644 --- a/src/js/game/systems/item_acceptor.js +++ b/src/js/game/systems/item_acceptor.js @@ -56,6 +56,36 @@ export class ItemAcceptorSystem extends GameSystemWithFilter { } } + updateForScreenshot() { + // Compute how much ticks we missed + const numTicks = this.accumulatedTicksWhileInMapOverview; + const progress = + this.root.dynamicTickrate.deltaSeconds * + 2 * + this.root.hubGoals.getBeltBaseSpeed() * + globalConfig.itemSpacingOnBelts * // * 2 because its only a half tile + numTicks; + + // Reset accumulated ticks + this.accumulatedTicksWhileInMapOverview = 0; + + for (let i = 0; i < this.allEntities.length; ++i) { + const entity = this.allEntities[i]; + const aceptorComp = entity.components.ItemAcceptor; + const animations = aceptorComp.itemConsumptionAnimations; + + // Process item consumption animations to avoid items popping from the belts + for (let animIndex = 0; animIndex < animations.length; ++animIndex) { + const anim = animations[animIndex]; + anim.animProgress += progress; + if (anim.animProgress > 1) { + fastArrayDelete(animations, animIndex); + animIndex -= 1; + } + } + } + } + /** * @param {DrawParameters} parameters * @param {MapChunkView} chunk From 19b0fc0e96b8ff8780ee9d54062011af1cee9004 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Fri, 4 Jun 2021 23:44:28 -0500 Subject: [PATCH 22/24] hide wires layer option pre-wires layer --- src/js/game/hud/parts/screenshot_exporter.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index 96841846..bc3aed09 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -19,6 +19,7 @@ import { getDeviceDPI } from "../../../core/dpi_manager"; import { HUDMassSelector } from "./mass_selector"; import { clamp } from "../../../core/utils"; import { CHUNK_OVERLAY_RES, MapChunkView } from "../../map_chunk_view"; +import { enumHubGoalRewards } from "../../tutorial_goals"; const logger = createLogger("screenshot_exporter"); @@ -125,7 +126,13 @@ export class HUDScreenshotExporter extends BaseHUDPart { }); const checkboxInputs = new FormElementCheckboxList({ id: "screenshotCheckboxes", - checkboxes: [overlayInput, layerInput, backgroundInput], + checkboxes: [ + overlayInput, + ...(this.root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_wires_painter_and_levers) + ? [layerInput] + : []), + backgroundInput, + ], }); const dialog = new DialogWithForm({ app: this.root.app, From 8b37453e0901e804097687d12342ebf6b4fcd2b1 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Sat, 5 Jun 2021 12:31:27 -0500 Subject: [PATCH 23/24] copy the check for if the wires overlay exists --- src/js/game/hud/parts/screenshot_exporter.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index bc3aed09..db10fa1a 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -337,7 +337,9 @@ export class HUDScreenshotExporter extends BaseHUDPart { this.root.systemMgr.systems.belt.drawBeltItems(parameters); this.root.map.drawForeground(parameters); this.root.systemMgr.systems.hub.draw(parameters); - this.root.hud.parts.wiresOverlay.draw(parameters); + if (this.root.hud.parts.wiresOverlay) { + this.root.hud.parts.wiresOverlay.draw(parameters); + } if (this.root.currentLayer === "wires") { this.root.map.drawWiresForegroundLayer(parameters); } From 731c1416cef2dde40caadfaa1fff6662e98dc28b Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Sat, 5 Jun 2021 14:32:28 -0500 Subject: [PATCH 24/24] fix call signature mismatch --- src/js/core/modal_dialog_forms.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/core/modal_dialog_forms.js b/src/js/core/modal_dialog_forms.js index 06bdafac..69fa5f44 100644 --- a/src/js/core/modal_dialog_forms.js +++ b/src/js/core/modal_dialog_forms.js @@ -170,7 +170,7 @@ export class FormElementCheckbox extends FormElement { this.element.classList.toggle("checked", this.value); } - focus(parent) {} + focus() {} } export class FormElementCheckboxList extends FormElement { @@ -195,7 +195,7 @@ export class FormElementCheckboxList extends FormElement { return this.checkboxes.map(checkbox => checkbox.getValue()); } - focus(parent) {} + focus() {} } export class FormElementItemChooser extends FormElement {