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:
parent
96170f8d22
commit
4ceb15051a
@ -215,24 +215,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkBoxFormElem {
|
.checkBoxFormElem,
|
||||||
|
.enumFormElem {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
@include S(margin, 10px, 0);
|
@include S(margin, 10px, 0);
|
||||||
|
|
||||||
> label {
|
> label {
|
||||||
@include S(margin-right, 10px);
|
@include S(margin-right, 10px);
|
||||||
}
|
}
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.enum {
|
.enum {
|
||||||
@include S(margin, 10px, 0);
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto 1fr auto;
|
grid-template-columns: auto 1fr auto;
|
||||||
@include S(grid-gap, 4px);
|
@include S(grid-gap, 4px);
|
||||||
@include S(width, 200px);
|
@include S(min-width, 160px);
|
||||||
|
|
||||||
> * {
|
> div {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -253,7 +257,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.toggle {
|
&.toggle {
|
||||||
@include S(width, 20px);
|
@include S(width, 16px);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.value {
|
&.value {
|
||||||
|
@ -9,37 +9,28 @@ import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
|||||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { DialogWithForm } from "../../../core/modal_dialog_elements";
|
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");
|
const logger = createLogger("screenshot_exporter");
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {{mode: string, resolution?: number}} QualityOptions
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {{id: string, options: QualityOptions}[]}
|
|
||||||
*/
|
|
||||||
const screenshotQualities = [
|
const screenshotQualities = [
|
||||||
{
|
{
|
||||||
id: "high",
|
id: "high",
|
||||||
options: { mode: "regular", resolution: 16384 },
|
resolution: 16384,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "medium",
|
id: "medium",
|
||||||
options: { mode: "regular", resolution: 4096 },
|
resolution: 4096,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "low",
|
id: "low",
|
||||||
options: { mode: "regular", resolution: 1024 },
|
resolution: 1024,
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "map",
|
|
||||||
options: { mode: "map" },
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
// @TODO: translation (T.dialogs.exportScreenshotWarning.qualities)
|
// @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 {
|
export class HUDScreenshotExporter extends BaseHUDPart {
|
||||||
createElements() {}
|
createElements() {}
|
||||||
@ -56,10 +47,17 @@ export class HUDScreenshotExporter extends BaseHUDPart {
|
|||||||
|
|
||||||
const qualityInput = new FormElementEnum({
|
const qualityInput = new FormElementEnum({
|
||||||
id: "screenshotQuality",
|
id: "screenshotQuality",
|
||||||
|
label: "Quality",
|
||||||
options: screenshotQualities,
|
options: screenshotQualities,
|
||||||
valueGetter: quality => quality.options,
|
valueGetter: quality => quality.resolution,
|
||||||
// @TODO: translation (T.dialogs.exportScreenshotWarning.qualityLabel)
|
// @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({
|
const layerInput = new FormElementCheckbox({
|
||||||
id: "screenshotLayer",
|
id: "screenshotLayer",
|
||||||
@ -71,22 +69,24 @@ export class HUDScreenshotExporter extends BaseHUDPart {
|
|||||||
app: this.root.app,
|
app: this.root.app,
|
||||||
title: T.dialogs.exportScreenshotWarning.title,
|
title: T.dialogs.exportScreenshotWarning.title,
|
||||||
desc: T.dialogs.exportScreenshotWarning.desc,
|
desc: T.dialogs.exportScreenshotWarning.desc,
|
||||||
formElements: [qualityInput, layerInput],
|
formElements: [qualityInput, overlayInput, layerInput],
|
||||||
buttons: ["cancel:good", "ok:bad"],
|
buttons: ["cancel:good", "ok:bad"],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.root.hud.parts.dialogs.internalShowDialog(dialog);
|
this.root.hud.parts.dialogs.internalShowDialog(dialog);
|
||||||
dialog.buttonSignals.ok.add(
|
dialog.buttonSignals.ok.add(
|
||||||
() => this.doExport(layerInput.getValue(), qualityInput.getValue()),
|
() => this.doExport(qualityInput.getValue(), overlayInput.getValue(), layerInput.getValue()),
|
||||||
this
|
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 {boolean} wiresLayer
|
||||||
* @param {QualityOptions} options
|
|
||||||
*/
|
*/
|
||||||
doExport(wiresLayer, options) {
|
doExport(resolution, overlay, wiresLayer) {
|
||||||
logger.log("Starting export ...");
|
logger.log("Starting export ...");
|
||||||
|
|
||||||
// Find extends
|
// Find extends
|
||||||
@ -114,15 +114,28 @@ export class HUDScreenshotExporter extends BaseHUDPart {
|
|||||||
// we want integer pixels per tile
|
// we want integer pixels per tile
|
||||||
// if resolution too low, we want integer pixels per chunk
|
// if resolution too low, we want integer pixels per chunk
|
||||||
const chunkSizePixels =
|
const chunkSizePixels =
|
||||||
maxDimensions * globalConfig.mapChunkSize > options.resolution
|
maxDimensions * globalConfig.mapChunkSize > resolution
|
||||||
? Math.max(1, Math.floor(options.resolution / maxDimensions))
|
? Math.max(1, Math.floor(resolution / maxDimensions))
|
||||||
: Math.floor(options.resolution / (maxDimensions * globalConfig.mapChunkSize)) *
|
: Math.floor(resolution / (maxDimensions * globalConfig.mapChunkSize)) *
|
||||||
globalConfig.mapChunkSize;
|
globalConfig.mapChunkSize;
|
||||||
logger.log("ChunkSizePixels:", chunkSizePixels);
|
logger.log("ChunkSizePixels:", chunkSizePixels);
|
||||||
|
|
||||||
|
// equivalent to zoomLevel
|
||||||
const chunkScale = chunkSizePixels / globalConfig.mapChunkWorldSize;
|
const chunkScale = chunkSizePixels / globalConfig.mapChunkWorldSize;
|
||||||
logger.log("Scale:", chunkScale);
|
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");
|
logger.log("Allocating buffer, if the factory grew too big it will crash here");
|
||||||
const [canvas, context] = makeOffscreenBuffer(
|
const [canvas, context] = makeOffscreenBuffer(
|
||||||
dimensions.x * chunkSizePixels,
|
dimensions.x * chunkSizePixels,
|
||||||
@ -144,7 +157,7 @@ export class HUDScreenshotExporter extends BaseHUDPart {
|
|||||||
const parameters = new DrawParameters({
|
const parameters = new DrawParameters({
|
||||||
context,
|
context,
|
||||||
visibleRect,
|
visibleRect,
|
||||||
desiredAtlasScale: 0.25,
|
desiredAtlasScale,
|
||||||
root: this.root,
|
root: this.root,
|
||||||
zoomLevel: chunkScale,
|
zoomLevel: chunkScale,
|
||||||
});
|
});
|
||||||
@ -152,17 +165,36 @@ export class HUDScreenshotExporter extends BaseHUDPart {
|
|||||||
context.scale(chunkScale, chunkScale);
|
context.scale(chunkScale, chunkScale);
|
||||||
context.translate(-visibleRect.x, -visibleRect.y);
|
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
|
// Render all relevant chunks
|
||||||
this.root.signals.gameFrameStarted.dispatch();
|
this.root.signals.gameFrameStarted.dispatch();
|
||||||
this.root.map.drawBackground(parameters);
|
if (overlay) {
|
||||||
this.root.systemMgr.systems.belt.drawBeltItems(parameters);
|
this.root;
|
||||||
this.root.map.drawForeground(parameters);
|
this.root.map.drawOverlay(parameters);
|
||||||
this.root.systemMgr.systems.hub.draw(parameters);
|
} else {
|
||||||
if (wiresLayer) {
|
this.root.map.drawBackground(parameters);
|
||||||
this.root.hud.parts.wiresOverlay.draw(parameters, true);
|
this.root.systemMgr.systems.belt.drawBeltItems(parameters);
|
||||||
this.root.map.drawWiresForegroundLayer(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
|
// Offer export
|
||||||
logger.log("Rendered buffer, exporting ...");
|
logger.log("Rendered buffer, exporting ...");
|
||||||
const image = canvas.toDataURL("image/png");
|
const image = canvas.toDataURL("image/png");
|
||||||
|
@ -114,10 +114,9 @@ export class HUDWiresOverlay extends BaseHUDPart {
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {DrawParameters} parameters
|
* @param {DrawParameters} parameters
|
||||||
* @param {boolean=} forced
|
|
||||||
*/
|
*/
|
||||||
draw(parameters, forced = false) {
|
draw(parameters) {
|
||||||
if (!forced && this.currentAlpha < 0.02) {
|
if (this.currentAlpha < 0.02) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +127,7 @@ export class HUDWiresOverlay extends BaseHUDPart {
|
|||||||
|
|
||||||
const bounds = parameters.visibleRect;
|
const bounds = parameters.visibleRect;
|
||||||
|
|
||||||
parameters.context.globalAlpha = forced ? 1 : this.currentAlpha;
|
parameters.context.globalAlpha = this.currentAlpha;
|
||||||
|
|
||||||
const scaleFactor = 1 / wiresBackgroundDpi;
|
const scaleFactor = 1 / wiresBackgroundDpi;
|
||||||
parameters.context.globalCompositeOperation = "overlay";
|
parameters.context.globalCompositeOperation = "overlay";
|
||||||
|
Loading…
Reference in New Issue
Block a user