timelapse replay layout edits then map edits
This commit is contained in:
parent
cd5b1f98d2
commit
99eb92c3b2
3 changed files with 121 additions and 87 deletions
|
@ -27,6 +27,7 @@ public:
|
||||||
private:
|
private:
|
||||||
Ui::MapImageExporter *ui;
|
Ui::MapImageExporter *ui;
|
||||||
|
|
||||||
|
Layout *layout = nullptr;
|
||||||
Map *map = nullptr;
|
Map *map = nullptr;
|
||||||
Editor *editor = nullptr;
|
Editor *editor = nullptr;
|
||||||
QGraphicsScene *scene = nullptr;
|
QGraphicsScene *scene = nullptr;
|
||||||
|
|
|
@ -1208,6 +1208,7 @@ void MainWindow::scrollTreeView(QString itemName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// !TODO: remove this?
|
||||||
void MainWindow::sortMapList() {
|
void MainWindow::sortMapList() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2564,6 +2565,17 @@ void MainWindow::on_action_Export_Map_Image_triggered() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionExport_Stitched_Map_Image_triggered() {
|
void MainWindow::on_actionExport_Stitched_Map_Image_triggered() {
|
||||||
|
if (!this->editor->map) {
|
||||||
|
QMessageBox warning(this);
|
||||||
|
warning.setText("Notice");
|
||||||
|
warning.setInformativeText("Map stich images are not possible without a map selected.");
|
||||||
|
warning.setStandardButtons(QMessageBox::Ok);
|
||||||
|
warning.setDefaultButton(QMessageBox::Cancel);
|
||||||
|
warning.setIcon(QMessageBox::Warning);
|
||||||
|
|
||||||
|
warning.exec();
|
||||||
|
return;
|
||||||
|
}
|
||||||
showExportMapImageWindow(ImageExporterMode::Stitch);
|
showExportMapImageWindow(ImageExporterMode::Stitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,15 +29,18 @@ MapImageExporter::MapImageExporter(QWidget *parent_, Editor *editor_, ImageExpor
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
this->map = editor_->map;
|
this->map = editor_->map;
|
||||||
|
this->layout = editor_->layout;
|
||||||
this->editor = editor_;
|
this->editor = editor_;
|
||||||
this->mode = mode;
|
this->mode = mode;
|
||||||
this->setWindowTitle(getTitle(this->mode));
|
this->setWindowTitle(getTitle(this->mode));
|
||||||
this->ui->groupBox_Connections->setVisible(this->mode == ImageExporterMode::Normal);
|
this->ui->groupBox_Connections->setVisible(this->mode == ImageExporterMode::Normal);
|
||||||
this->ui->groupBox_Timelapse->setVisible(this->mode == ImageExporterMode::Timelapse);
|
this->ui->groupBox_Timelapse->setVisible(this->mode == ImageExporterMode::Timelapse);
|
||||||
|
|
||||||
this->ui->comboBox_MapSelection->addItems(editor->project->mapNames);
|
if (this->map) {
|
||||||
this->ui->comboBox_MapSelection->setCurrentText(map->name);
|
this->ui->comboBox_MapSelection->addItems(editor->project->mapNames);
|
||||||
this->ui->comboBox_MapSelection->setEnabled(false);// TODO: allow selecting map from drop-down
|
this->ui->comboBox_MapSelection->setCurrentText(map->name);
|
||||||
|
this->ui->comboBox_MapSelection->setEnabled(false);// TODO: allow selecting map from drop-down
|
||||||
|
}
|
||||||
|
|
||||||
updatePreview();
|
updatePreview();
|
||||||
}
|
}
|
||||||
|
@ -53,13 +56,13 @@ void MapImageExporter::saveImage() {
|
||||||
switch (this->mode)
|
switch (this->mode)
|
||||||
{
|
{
|
||||||
case ImageExporterMode::Normal:
|
case ImageExporterMode::Normal:
|
||||||
defaultFilename = map->name;
|
defaultFilename = this->map? this->map->name : this->layout->name;
|
||||||
break;
|
break;
|
||||||
case ImageExporterMode::Stitch:
|
case ImageExporterMode::Stitch:
|
||||||
defaultFilename = QString("Stitch_From_%1").arg(map->name);
|
defaultFilename = QString("Stitch_From_%1").arg(this->map? this->map->name : this->layout->name);
|
||||||
break;
|
break;
|
||||||
case ImageExporterMode::Timelapse:
|
case ImageExporterMode::Timelapse:
|
||||||
defaultFilename = QString("Timelapse_%1").arg(map->name);
|
defaultFilename = QString("Timelapse_%1").arg(this->map? this->map->name : this->layout->name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,89 +94,98 @@ void MapImageExporter::saveImage() {
|
||||||
}
|
}
|
||||||
case ImageExporterMode::Timelapse:
|
case ImageExporterMode::Timelapse:
|
||||||
// !TODO: also need layout editHistory!
|
// !TODO: also need layout editHistory!
|
||||||
QProgressDialog progress("Building map timelapse...", "Cancel", 0, 1, this);
|
QGifImage timelapseImg;
|
||||||
progress.setAutoClose(true);
|
|
||||||
progress.setWindowModality(Qt::WindowModal);
|
|
||||||
progress.setModal(true);
|
|
||||||
progress.setMaximum(1);
|
|
||||||
progress.setValue(0);
|
|
||||||
|
|
||||||
Layout *layout = this->map->layout;
|
|
||||||
if (!layout) break;
|
|
||||||
|
|
||||||
int maxWidth = layout->getWidth() * 16;
|
|
||||||
int maxHeight = layout->getHeight() * 16;
|
|
||||||
if (showBorder) {
|
|
||||||
maxWidth += 2 * STITCH_MODE_BORDER_DISTANCE * 16;
|
|
||||||
maxHeight += 2 * STITCH_MODE_BORDER_DISTANCE * 16;
|
|
||||||
}
|
|
||||||
// Rewind to the specified start of the map edit history.
|
|
||||||
int i = 0;
|
|
||||||
while (this->map->editHistory.canUndo()) {
|
|
||||||
progress.setValue(i);
|
|
||||||
this->map->editHistory.undo();
|
|
||||||
int width = this->map->getWidth() * 16;
|
|
||||||
int height = this->map->getHeight() * 16;
|
|
||||||
if (showBorder) {
|
|
||||||
width += 2 * STITCH_MODE_BORDER_DISTANCE * 16;
|
|
||||||
height += 2 * STITCH_MODE_BORDER_DISTANCE * 16;
|
|
||||||
}
|
|
||||||
if (width > maxWidth) {
|
|
||||||
maxWidth = width;
|
|
||||||
}
|
|
||||||
if (height > maxHeight) {
|
|
||||||
maxHeight = height;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
QGifImage timelapseImg(QSize(maxWidth, maxHeight));
|
|
||||||
timelapseImg.setDefaultDelay(timelapseDelayMs);
|
timelapseImg.setDefaultDelay(timelapseDelayMs);
|
||||||
timelapseImg.setDefaultTransparentColor(QColor(0, 0, 0));
|
timelapseImg.setDefaultTransparentColor(QColor(0, 0, 0));
|
||||||
// Draw each frame, skpping the specified number of map edits in
|
|
||||||
// the undo history.
|
auto generateTimelapseFromHistory = [=, this, &timelapseImg](QString progressText, QUndoStack &historyStack){
|
||||||
progress.setMaximum(i);
|
//
|
||||||
while (i > 0) {
|
QProgressDialog progress(progressText, "Cancel", 0, 1, this);
|
||||||
if (progress.wasCanceled()) {
|
progress.setAutoClose(true);
|
||||||
progress.close();
|
progress.setWindowModality(Qt::WindowModal);
|
||||||
while (i > 0 && this->map->editHistory.canRedo()) {
|
progress.setModal(true);
|
||||||
i--;
|
progress.setMaximum(1);
|
||||||
this->map->editHistory.redo();
|
progress.setValue(0);
|
||||||
|
|
||||||
|
int maxWidth = this->layout->getWidth() * 16;
|
||||||
|
int maxHeight = this->layout->getHeight() * 16;
|
||||||
|
if (showBorder) {
|
||||||
|
maxWidth += 2 * STITCH_MODE_BORDER_DISTANCE * 16;
|
||||||
|
maxHeight += 2 * STITCH_MODE_BORDER_DISTANCE * 16;
|
||||||
|
}
|
||||||
|
// Rewind to the specified start of the map edit history.
|
||||||
|
int i = 0;
|
||||||
|
while (historyStack.canUndo()) {
|
||||||
|
progress.setValue(i);
|
||||||
|
historyStack.undo();
|
||||||
|
int width = this->layout->getWidth() * 16;
|
||||||
|
int height = this->layout->getHeight() * 16;
|
||||||
|
if (showBorder) {
|
||||||
|
width += 2 * STITCH_MODE_BORDER_DISTANCE * 16;
|
||||||
|
height += 2 * STITCH_MODE_BORDER_DISTANCE * 16;
|
||||||
}
|
}
|
||||||
return;
|
if (width > maxWidth) {
|
||||||
|
maxWidth = width;
|
||||||
|
}
|
||||||
|
if (height > maxHeight) {
|
||||||
|
maxHeight = height;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
while (this->map->editHistory.canRedo() &&
|
|
||||||
!historyItemAppliesToFrame(this->map->editHistory.command(this->map->editHistory.index()))) {
|
// Draw each frame, skpping the specified number of map edits in
|
||||||
i--;
|
// the undo history.
|
||||||
this->map->editHistory.redo();
|
progress.setMaximum(i);
|
||||||
}
|
while (i > 0) {
|
||||||
progress.setValue(progress.maximum() - i);
|
if (progress.wasCanceled()) {
|
||||||
QPixmap pixmap = this->getFormattedMapPixmap(this->map, !this->showBorder);
|
progress.close();
|
||||||
if (pixmap.width() < maxWidth || pixmap.height() < maxHeight) {
|
while (i > 0 && historyStack.canRedo()) {
|
||||||
QPixmap pixmap2 = QPixmap(maxWidth, maxHeight);
|
|
||||||
QPainter painter(&pixmap2);
|
|
||||||
pixmap2.fill(QColor(0, 0, 0));
|
|
||||||
painter.drawPixmap(0, 0, pixmap.width(), pixmap.height(), pixmap);
|
|
||||||
painter.end();
|
|
||||||
pixmap = pixmap2;
|
|
||||||
}
|
|
||||||
timelapseImg.addFrame(pixmap.toImage());
|
|
||||||
for (int j = 0; j < timelapseSkipAmount; j++) {
|
|
||||||
if (i > 0) {
|
|
||||||
i--;
|
|
||||||
this->map->editHistory.redo();
|
|
||||||
while (this->map->editHistory.canRedo() &&
|
|
||||||
!historyItemAppliesToFrame(this->map->editHistory.command(this->map->editHistory.index()))) {
|
|
||||||
i--;
|
i--;
|
||||||
this->map->editHistory.redo();
|
historyStack.redo();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (historyStack.canRedo() &&
|
||||||
|
!historyItemAppliesToFrame(historyStack.command(historyStack.index()))) {
|
||||||
|
i--;
|
||||||
|
historyStack.redo();
|
||||||
|
}
|
||||||
|
progress.setValue(progress.maximum() - i);
|
||||||
|
QPixmap pixmap = this->getFormattedMapPixmap(this->map, !this->showBorder);
|
||||||
|
if (pixmap.width() < maxWidth || pixmap.height() < maxHeight) {
|
||||||
|
QPixmap pixmap2 = QPixmap(maxWidth, maxHeight);
|
||||||
|
QPainter painter(&pixmap2);
|
||||||
|
pixmap2.fill(QColor(0, 0, 0));
|
||||||
|
painter.drawPixmap(0, 0, pixmap.width(), pixmap.height(), pixmap);
|
||||||
|
painter.end();
|
||||||
|
pixmap = pixmap2;
|
||||||
|
}
|
||||||
|
timelapseImg.addFrame(pixmap.toImage());
|
||||||
|
for (int j = 0; j < timelapseSkipAmount; j++) {
|
||||||
|
if (i > 0) {
|
||||||
|
i--;
|
||||||
|
historyStack.redo();
|
||||||
|
while (historyStack.canRedo() &&
|
||||||
|
!historyItemAppliesToFrame(historyStack.command(historyStack.index()))) {
|
||||||
|
i--;
|
||||||
|
historyStack.redo();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// The latest map state is the last animated frame.
|
||||||
// The latest map state is the last animated frame.
|
QPixmap pixmap = this->getFormattedMapPixmap(this->map, !this->showBorder);
|
||||||
QPixmap pixmap = this->getFormattedMapPixmap(this->map, !this->showBorder);
|
timelapseImg.addFrame(pixmap.toImage());
|
||||||
timelapseImg.addFrame(pixmap.toImage());
|
progress.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this->layout)
|
||||||
|
generateTimelapseFromHistory("Building layout timelapse...", this->layout->editHistory);
|
||||||
|
|
||||||
|
if (this->map)
|
||||||
|
generateTimelapseFromHistory("Building map timelapse...", this->map->editHistory);
|
||||||
|
|
||||||
timelapseImg.save(filepath);
|
timelapseImg.save(filepath);
|
||||||
progress.close();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this->close();
|
this->close();
|
||||||
|
@ -358,17 +370,22 @@ void MapImageExporter::updatePreview() {
|
||||||
scene->itemsBoundingRect().height() + 2);
|
scene->itemsBoundingRect().height() + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// THIS
|
||||||
QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
|
QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
|
||||||
QPixmap pixmap;
|
QPixmap pixmap;
|
||||||
|
|
||||||
// draw background layer / base image
|
Layout *layout;
|
||||||
Layout *layout = map->layout;
|
|
||||||
if (!layout) {
|
|
||||||
return QPixmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
layout->render(true);
|
// draw background layer / base image
|
||||||
pixmap = layout->pixmap;
|
if (!this->map) {
|
||||||
|
layout = this->layout;
|
||||||
|
layout->render(true);
|
||||||
|
pixmap = layout->pixmap;
|
||||||
|
} else {
|
||||||
|
layout = map->layout;
|
||||||
|
map->layout->render(true);
|
||||||
|
pixmap = map->layout->pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
if (showCollision) {
|
if (showCollision) {
|
||||||
QPainter collisionPainter(&pixmap);
|
QPainter collisionPainter(&pixmap);
|
||||||
|
@ -401,6 +418,10 @@ QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
|
||||||
pixmap = newPixmap;
|
pixmap = newPixmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this->map) {
|
||||||
|
return pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this->mode) {
|
if (!this->mode) {
|
||||||
// if showing connections, draw on outside of image
|
// if showing connections, draw on outside of image
|
||||||
QPainter connectionPainter(&pixmap);
|
QPainter connectionPainter(&pixmap);
|
||||||
|
|
Loading…
Reference in a new issue