2020-06-13 08:57:29 +00:00
|
|
|
import { BaseHUDPart } from "../base_hud_part";
|
|
|
|
import { KEYMAPPINGS } from "../../key_action_mapper";
|
|
|
|
import { IS_DEMO, globalConfig } from "../../../core/config";
|
|
|
|
import { T } from "../../../translations";
|
|
|
|
import { createLogger } from "../../../core/logging";
|
|
|
|
import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
|
|
|
import { Vector } from "../../../core/vector";
|
|
|
|
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
|
|
|
|
import { DrawParameters } from "../../../core/draw_parameters";
|
|
|
|
import { Rectangle } from "../../../core/rectangle";
|
|
|
|
|
|
|
|
const logger = createLogger("screenshot_exporter");
|
|
|
|
|
|
|
|
export class HUDScreenshotExporter extends BaseHUDPart {
|
|
|
|
createElements() {}
|
|
|
|
|
|
|
|
initialize() {
|
|
|
|
this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.exportScreenshot).add(this.startExport, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
startExport() {
|
|
|
|
if (IS_DEMO) {
|
|
|
|
this.root.hud.parts.dialogs.showFeatureRestrictionInfo(T.demo.features.exportingBase);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const { ok } = this.root.hud.parts.dialogs.showInfo(
|
|
|
|
T.dialogs.exportScreenshotWarning.title,
|
|
|
|
T.dialogs.exportScreenshotWarning.desc,
|
|
|
|
["cancel:good", "ok:bad"]
|
|
|
|
);
|
|
|
|
ok.add(this.doExport, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
doExport() {
|
|
|
|
logger.log("Starting export ...");
|
|
|
|
|
|
|
|
// 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 bounds = staticEntities[i].components.StaticMapEntity.getTileSpaceBounds();
|
2020-06-27 08:51:52 +00:00
|
|
|
minTile.x = Math.min(minTile.x, bounds.x);
|
|
|
|
minTile.y = Math.min(minTile.y, bounds.y);
|
2020-06-13 08:57:29 +00:00
|
|
|
|
2020-06-27 08:51:52 +00:00
|
|
|
maxTile.x = Math.max(maxTile.x, bounds.x + bounds.w);
|
|
|
|
maxTile.y = Math.max(maxTile.y, bounds.y + bounds.h);
|
2020-06-13 08:57:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const minChunk = minTile.divideScalar(globalConfig.mapChunkSize).floor();
|
|
|
|
const maxChunk = maxTile.divideScalar(globalConfig.mapChunkSize).ceil();
|
|
|
|
|
|
|
|
const dimensions = maxChunk.sub(minChunk);
|
|
|
|
logger.log("Dimensions:", dimensions);
|
2020-06-17 18:11:55 +00:00
|
|
|
|
|
|
|
let chunkSizePixels = 128;
|
2020-06-27 08:51:52 +00:00
|
|
|
const maxDimensions = Math.max(dimensions.x, dimensions.y);
|
2020-06-17 18:33:20 +00:00
|
|
|
|
2020-06-17 18:31:39 +00:00
|
|
|
if (maxDimensions > 128) {
|
2020-06-27 08:51:52 +00:00
|
|
|
chunkSizePixels = Math.max(1, Math.floor(128 * (128 / maxDimensions)));
|
2020-06-17 18:11:55 +00:00
|
|
|
}
|
2020-06-17 18:31:39 +00:00
|
|
|
logger.log("ChunkSizePixels:", chunkSizePixels);
|
2020-06-17 18:11:55 +00:00
|
|
|
|
2020-08-14 07:38:48 +00:00
|
|
|
const chunkScale = chunkSizePixels / globalConfig.mapChunkWorldSize;
|
2020-06-13 08:57:29 +00:00
|
|
|
logger.log("Scale:", chunkScale);
|
|
|
|
|
|
|
|
logger.log("Allocating buffer, if the factory grew too big it will crash here");
|
|
|
|
const [canvas, context] = makeOffscreenBuffer(
|
|
|
|
dimensions.x * chunkSizePixels,
|
|
|
|
dimensions.y * chunkSizePixels,
|
|
|
|
{
|
|
|
|
smooth: true,
|
|
|
|
reusable: false,
|
|
|
|
label: "export-buffer",
|
|
|
|
}
|
|
|
|
);
|
|
|
|
logger.log("Got buffer, rendering now ...");
|
|
|
|
|
|
|
|
const visibleRect = new Rectangle(
|
2020-08-14 07:38:48 +00:00
|
|
|
minChunk.x * globalConfig.mapChunkWorldSize,
|
|
|
|
minChunk.y * globalConfig.mapChunkWorldSize,
|
|
|
|
dimensions.x * globalConfig.mapChunkWorldSize,
|
|
|
|
dimensions.y * globalConfig.mapChunkWorldSize
|
2020-06-13 08:57:29 +00:00
|
|
|
);
|
|
|
|
const parameters = new DrawParameters({
|
|
|
|
context,
|
|
|
|
visibleRect,
|
2020-09-22 08:32:13 +00:00
|
|
|
desiredAtlasScale: chunkScale,
|
2020-06-13 08:57:29 +00:00
|
|
|
root: this.root,
|
|
|
|
zoomLevel: chunkScale,
|
|
|
|
});
|
|
|
|
|
|
|
|
context.scale(chunkScale, chunkScale);
|
|
|
|
context.translate(-visibleRect.x, -visibleRect.y);
|
|
|
|
|
|
|
|
// Render all relevant chunks
|
|
|
|
this.root.map.drawBackground(parameters);
|
|
|
|
this.root.map.drawForeground(parameters);
|
|
|
|
|
|
|
|
// Offer export
|
|
|
|
logger.log("Rendered buffer, exporting ...");
|
|
|
|
const image = canvas.toDataURL("image/png");
|
|
|
|
const link = document.createElement("a");
|
|
|
|
link.download = "base.png";
|
|
|
|
link.href = image;
|
|
|
|
link.click();
|
|
|
|
logger.log("Done!");
|
|
|
|
}
|
|
|
|
}
|