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";