1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-06-13 13:04:03 +00:00

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.
This commit is contained in:
EmeraldBlock 2021-03-31 18:15:50 -05:00
parent 96170f8d22
commit 4ceb15051a
3 changed files with 79 additions and 44 deletions

View File

@ -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 {

View File

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

View File

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