leocad/qt/lc_renderdialog.cpp

314 lines
7.1 KiB
C++
Raw Normal View History

2017-09-22 19:08:02 +02:00
#include "lc_global.h"
#include "lc_renderdialog.h"
#include "ui_lc_renderdialog.h"
#include "project.h"
#include "lc_application.h"
2017-11-03 01:35:12 +01:00
#include "lc_profile.h"
2017-09-22 19:08:02 +02:00
2017-11-05 02:54:12 +01:00
#define LC_POVRAY_PREVIEW_WIDTH 768
#define LC_POVRAY_PREVIEW_HEIGHT 432
#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
#define LC_POVRAY_MEMORY_MAPPED_FILE 1
#endif
2017-11-05 02:54:12 +01:00
2017-09-22 19:08:02 +02:00
lcRenderDialog::lcRenderDialog(QWidget* Parent)
: QDialog(Parent),
2018-01-15 19:48:34 +01:00
ui(new Ui::lcRenderDialog)
2017-09-22 19:08:02 +02:00
{
2017-12-07 07:08:56 +01:00
#ifndef QT_NO_PROCESS
2017-09-22 19:08:02 +02:00
mProcess = nullptr;
2017-12-07 07:08:56 +01:00
#endif
2018-01-15 19:48:34 +01:00
mOutputBuffer = nullptr;
2017-09-22 19:08:02 +02:00
ui->setupUi(this);
2017-11-04 00:01:30 +01:00
ui->WidthEdit->setText(QString::number(lcGetProfileInt(LC_PROFILE_POVRAY_WIDTH)));
ui->WidthEdit->setValidator(new QIntValidator(16, INT_MAX));
ui->HeightEdit->setText(QString::number(lcGetProfileInt(LC_PROFILE_POVRAY_HEIGHT)));
ui->HeightEdit->setValidator(new QIntValidator(16, INT_MAX));
ui->OutputEdit->setText(lcGetActiveProject()->GetImageFileName(false));
2017-11-04 00:01:30 +01:00
2017-11-05 02:54:12 +01:00
QImage Image(LC_POVRAY_PREVIEW_WIDTH, LC_POVRAY_PREVIEW_HEIGHT, QImage::Format_RGB32);
Image.fill(QColor(255, 255, 255));
ui->preview->setPixmap(QPixmap::fromImage(Image));
2017-11-05 02:54:12 +01:00
2017-09-22 19:08:02 +02:00
connect(&mUpdateTimer, SIGNAL(timeout()), this, SLOT(Update()));
mUpdateTimer.start(500);
2017-09-22 19:08:02 +02:00
}
lcRenderDialog::~lcRenderDialog()
{
delete ui;
}
QString lcRenderDialog::GetOutputFileName() const
{
return QDir(QDir::tempPath()).absoluteFilePath("leocad-render.out");
}
2017-11-03 01:35:12 +01:00
QString lcRenderDialog::GetPOVFileName() const
{
return QDir(QDir::tempPath()).absoluteFilePath("leocad-render.pov");
}
2017-11-05 02:54:12 +01:00
void lcRenderDialog::CloseProcess()
2017-11-04 00:01:30 +01:00
{
2017-12-07 07:08:56 +01:00
#ifndef QT_NO_PROCESS
2017-11-05 02:54:12 +01:00
delete mProcess;
mProcess = nullptr;
2017-12-07 07:08:56 +01:00
#endif
#if LC_POVRAY_MEMORY_MAPPED_FILE
mOutputFile.unmap((uchar*)mOutputBuffer);
mOutputBuffer = nullptr;
mOutputFile.close();
QFile::remove(GetOutputFileName());
#endif
2017-11-05 02:54:12 +01:00
QFile::remove(GetPOVFileName());
ui->RenderButton->setText(tr("Render"));
2017-11-04 00:01:30 +01:00
}
2017-11-05 02:54:12 +01:00
bool lcRenderDialog::PromptCancel()
2017-09-22 19:08:02 +02:00
{
2017-12-07 07:08:56 +01:00
#ifndef QT_NO_PROCESS
2017-09-22 19:08:02 +02:00
if (mProcess)
{
2017-11-05 02:54:12 +01:00
if (QMessageBox::question(this, tr("Cancel Render"), tr("Are you sure you want to cancel the current render?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
{
if (mProcess)
{
mProcess->kill();
CloseProcess();
}
}
else
return false;
2017-09-22 19:08:02 +02:00
}
2017-12-07 07:08:56 +01:00
#endif
2017-11-05 02:54:12 +01:00
return true;
}
void lcRenderDialog::reject()
{
if (PromptCancel())
QDialog::reject();
}
void lcRenderDialog::on_RenderButton_clicked()
{
2017-12-07 07:08:56 +01:00
#ifndef QT_NO_PROCESS
if (mProcess)
{
PromptCancel();
2017-11-05 02:54:12 +01:00
return;
}
2017-11-05 02:54:12 +01:00
2017-11-03 01:35:12 +01:00
QString FileName = GetPOVFileName();
2017-09-22 19:08:02 +02:00
if (!lcGetActiveProject()->ExportPOVRay(FileName))
return;
QStringList Arguments;
Arguments.append(QString::fromLatin1("+I%1").arg(FileName));
2017-11-04 00:01:30 +01:00
Arguments.append(QString::fromLatin1("+W%1").arg(ui->WidthEdit->text()));
Arguments.append(QString::fromLatin1("+H%1").arg(ui->HeightEdit->text()));
2017-11-05 02:54:12 +01:00
Arguments.append("-O-");
2017-09-22 19:08:02 +02:00
#if LC_POVRAY_MEMORY_MAPPED_FILE
Arguments.append(QString::fromLatin1("+SM%1").arg(GetOutputFileName()));
#endif
2017-12-27 22:55:37 +01:00
int Quality = ui->QualityComboBox->currentIndex();
switch (Quality)
{
case 0:
Arguments.append("+Q11");
Arguments.append("+R3");
Arguments.append("+A0.1");
Arguments.append("+J0.5");
break;
case 1:
Arguments.append("+Q5");
Arguments.append("+A0.1");
break;
case 2:
break;
}
2017-09-22 19:08:02 +02:00
/*
if (!LGEOPath.isEmpty())
{
Arguments.append(QString::fromLatin1("+L%1lg/").arg(LGEOPath));
Arguments.append(QString::fromLatin1("+L%1ar/").arg(LGEOPath));
}
*/
2017-11-03 01:35:12 +01:00
QString POVRayPath;
#ifdef Q_OS_WIN
2018-01-16 03:08:11 +01:00
POVRayPath = QDir::cleanPath(QCoreApplication::applicationDirPath() + QLatin1String("/povconsole32-sse2.exe"));
2017-11-03 01:35:12 +01:00
#endif
#ifdef Q_OS_LINUX
POVRayPath = lcGetProfileString(LC_PROFILE_POVRAY_PATH);
Arguments.append("+FN");
2017-11-03 01:35:12 +01:00
Arguments.append("-D");
#endif
#ifdef Q_OS_MACOS
2018-01-15 19:48:34 +01:00
POVRayPath = QDir::cleanPath(QCoreApplication::applicationDirPath() + QLatin1String("/povray"));
2017-11-03 01:35:12 +01:00
#endif
2017-09-22 19:08:02 +02:00
mProcess = new QProcess(this);
connect(mProcess, SIGNAL(readyReadStandardError()), this, SLOT(ReadStdErr()));
2017-09-22 19:08:02 +02:00
mProcess->start(POVRayPath, Arguments);
2017-11-03 01:35:12 +01:00
2017-11-05 02:54:12 +01:00
if (mProcess->waitForStarted())
{
2017-11-05 02:54:12 +01:00
ui->RenderButton->setText(tr("Cancel"));
ui->RenderProgress->setValue(ui->RenderProgress->minimum());
2019-03-10 01:38:54 +01:00
mStdErrList.clear();
}
2017-11-05 02:54:12 +01:00
else
2017-11-03 01:35:12 +01:00
{
QMessageBox::warning(this, tr("Error"), tr("Error starting POV-Ray."));
2017-11-05 02:54:12 +01:00
CloseProcess();
2017-11-03 01:35:12 +01:00
}
2017-12-07 07:08:56 +01:00
#endif
2017-09-22 19:08:02 +02:00
}
void lcRenderDialog::ReadStdErr()
{
2019-03-10 01:38:54 +01:00
QString StdErr = QString(mProcess->readAllStandardError());
mStdErrList.append(StdErr);
QRegExp RegexPovRayProgress("Rendered (\\d+) of (\\d+) pixels.*");
RegexPovRayProgress.setCaseSensitivity(Qt::CaseInsensitive);
if (RegexPovRayProgress.indexIn(StdErr) == 0)
{
2019-03-10 01:38:54 +01:00
ui->RenderProgress->setMaximum(RegexPovRayProgress.cap(2).toInt());
ui->RenderProgress->setValue(RegexPovRayProgress.cap(1).toInt());
}
}
2017-09-22 19:08:02 +02:00
void lcRenderDialog::Update()
{
2017-12-07 07:08:56 +01:00
#ifndef QT_NO_PROCESS
if (!mProcess)
return;
if (mProcess->state() == QProcess::NotRunning)
2017-09-22 19:08:02 +02:00
{
2017-11-03 01:35:12 +01:00
#ifdef Q_OS_LINUX
QByteArray Output = mProcess->readAllStandardOutput();
mImage = QImage::fromData(Output);
ShowResult();
2017-11-03 01:35:12 +01:00
#endif
CloseProcess();
2017-09-22 19:08:02 +02:00
}
2017-12-07 07:08:56 +01:00
#endif
2017-11-03 01:35:12 +01:00
#if LC_POVRAY_MEMORY_MAPPED_FILE
if (!mOutputBuffer)
{
mOutputFile.setFileName(GetOutputFileName());
2017-09-22 19:08:02 +02:00
if (!mOutputFile.open(QFile::ReadWrite))
return;
2017-09-22 19:08:02 +02:00
mOutputBuffer = mOutputFile.map(0, mOutputFile.size());
if (!mOutputBuffer)
{
mOutputFile.close();
return;
}
2017-11-05 02:54:12 +01:00
}
2017-09-22 19:08:02 +02:00
struct lcSharedMemoryHeader
{
2017-12-02 21:22:04 +01:00
quint32 Version;
quint32 Width;
quint32 Height;
quint32 PixelsWritten;
quint32 PixelsRead;
2017-09-22 19:08:02 +02:00
};
lcSharedMemoryHeader* Header = (lcSharedMemoryHeader*)mOutputBuffer;
2017-09-22 19:08:02 +02:00
if (Header->PixelsWritten == Header->PixelsRead)
return;
2017-09-22 19:08:02 +02:00
int Width = Header->Width;
int Height = Header->Height;
int PixelsWritten = Header->PixelsWritten;
2017-09-22 19:08:02 +02:00
if (!Header->PixelsRead)
mImage = QImage(Width, Height, QImage::Format_ARGB32);
2017-09-22 19:08:02 +02:00
2017-12-02 21:22:04 +01:00
quint8* Pixels = (quint8*)(Header + 1);
2017-09-22 19:08:02 +02:00
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
2017-12-21 03:18:22 +01:00
mImage.setPixel(x, y, qRgba(Pixels[0], Pixels[1], Pixels[2], Pixels[3]));
2017-09-22 19:08:02 +02:00
Pixels += 4;
}
}
Header->PixelsRead = PixelsWritten;
2017-09-22 19:08:02 +02:00
2017-12-27 22:55:37 +01:00
if (PixelsWritten == Width * Height)
ShowResult();
#endif
}
2017-12-27 22:55:37 +01:00
2019-03-10 01:38:54 +01:00
void lcRenderDialog::ShowResult()
{
ReadStdErr();
ui->RenderProgress->setValue(ui->RenderProgress->maximum());
2019-03-10 01:38:54 +01:00
if (mProcess->exitStatus() != QProcess::NormalExit || mProcess->exitCode() != 0)
{
QMessageBox error;
error.setWindowTitle(tr("Error"));
error.setIcon(QMessageBox::Critical);
error.setText(tr("An error occurred while rendering. Check details or try again."));
2019-03-10 01:38:54 +01:00
error.setDetailedText(mStdErrList.join(""));
error.exec();
return;
}
2017-12-27 22:55:37 +01:00
ui->preview->setPixmap(QPixmap::fromImage(mImage.scaled(LC_POVRAY_PREVIEW_WIDTH, LC_POVRAY_PREVIEW_HEIGHT, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
2017-12-27 22:55:37 +01:00
QString FileName = ui->OutputEdit->text();
if (!FileName.isEmpty())
{
QImageWriter Writer(FileName);
bool Result = Writer.write(mImage);
if (!Result)
QMessageBox::information(this, tr("Error"), tr("Error writing to file '%1':\n%2").arg(FileName, Writer.errorString()));
2017-12-27 22:55:37 +01:00
}
2017-09-22 19:08:02 +02:00
}
2017-12-27 22:55:37 +01:00
void lcRenderDialog::on_OutputBrowseButton_clicked()
{
QString Result = QFileDialog::getSaveFileName(this, tr("Select Output File"), ui->OutputEdit->text(), tr("Supported Image Files (*.bmp *.png *.jpg);;BMP Files (*.bmp);;PNG Files (*.png);;JPEG Files (*.jpg);;All Files (*.*)"));
if (!Result.isEmpty())
ui->OutputEdit->setText(QDir::toNativeSeparators(Result));
}