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
2018-01-15 06:45:50 +01:00
# 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 ) ,
2019-03-19 23:08:03 +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 ) ) ;
2018-04-15 03:27:16 +02:00
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 ) ) ;
2019-03-08 12:42:36 +01:00
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 ( ) ) ) ;
2017-12-10 01:27:56 +01:00
mUpdateTimer . start ( 500 ) ;
2017-09-22 19:08:02 +02:00
}
lcRenderDialog : : ~ lcRenderDialog ( )
{
delete ui ;
}
2018-01-15 06:45:50 +01:00
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
2018-01-15 06:45:50 +01:00
# 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
2017-12-10 01:27:56 +01:00
if ( mProcess )
{
PromptCancel ( ) ;
2017-11-05 02:54:12 +01:00
return ;
2017-12-10 01:27:56 +01:00
}
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
2018-01-15 06:45:50 +01: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 ) ;
2018-01-12 18:40:32 +01:00
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 ) ;
2019-03-19 23:08:03 +01:00
# ifdef Q_OS_LINUX
2019-03-08 12:42:36 +01:00
connect ( mProcess , SIGNAL ( readyReadStandardError ( ) ) , this , SLOT ( ReadStdErr ( ) ) ) ;
2019-03-19 23:08:03 +01:00
# endif
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 ( ) )
2019-03-08 12:42:36 +01:00
{
2017-11-05 02:54:12 +01:00
ui - > RenderButton - > setText ( tr ( " Cancel " ) ) ;
2019-03-08 12:42:36 +01:00
ui - > RenderProgress - > setValue ( ui - > RenderProgress - > minimum ( ) ) ;
2019-03-10 01:38:54 +01:00
mStdErrList . clear ( ) ;
2019-03-08 12:42:36 +01:00
}
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
}
2019-03-08 12:42:36 +01:00
void lcRenderDialog : : ReadStdErr ( )
{
2019-03-10 01:38:54 +01:00
QString StdErr = QString ( mProcess - > readAllStandardError ( ) ) ;
mStdErrList . append ( StdErr ) ;
2019-03-19 23:08:03 +01:00
# ifdef Q_OS_LINUX
2019-03-10 01:38:54 +01:00
QRegExp RegexPovRayProgress ( " Rendered ( \\ d+) of ( \ \ d + ) pixels . * " ) ;
RegexPovRayProgress . setCaseSensitivity ( Qt : : CaseInsensitive ) ;
if ( RegexPovRayProgress . indexIn ( StdErr ) = = 0 )
2019-03-08 12:42:36 +01:00
{
2019-03-10 01:38:54 +01:00
ui - > RenderProgress - > setMaximum ( RegexPovRayProgress . cap ( 2 ) . toInt ( ) ) ;
ui - > RenderProgress - > setValue ( RegexPovRayProgress . cap ( 1 ) . toInt ( ) ) ;
2019-03-08 12:42:36 +01:00
}
2019-03-19 23:08:03 +01:00
# endif
2019-03-08 12:42:36 +01:00
}
2017-09-22 19:08:02 +02:00
void lcRenderDialog : : Update ( )
{
2017-12-07 07:08:56 +01:00
# ifndef QT_NO_PROCESS
2017-12-10 01:27:56 +01:00
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
2017-12-10 01:27:56 +01:00
QByteArray Output = mProcess - > readAllStandardOutput ( ) ;
2019-03-08 12:42:36 +01:00
mImage = QImage : : fromData ( Output ) ;
ShowResult ( ) ;
2017-11-03 01:35:12 +01:00
# endif
2019-03-08 12:42:36 +01:00
2017-12-10 01:27:56 +01:00
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
2018-01-15 06:45:50 +01:00
# if LC_POVRAY_MEMORY_MAPPED_FILE
if ( ! mOutputBuffer )
{
mOutputFile . setFileName ( GetOutputFileName ( ) ) ;
2017-09-22 19:08:02 +02:00
2018-01-15 06:45:50 +01:00
if ( ! mOutputFile . open ( QFile : : ReadWrite ) )
return ;
2017-09-22 19:08:02 +02:00
2018-01-15 06:45:50 +01: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
} ;
2018-01-15 06:45:50 +01:00
lcSharedMemoryHeader * Header = ( lcSharedMemoryHeader * ) mOutputBuffer ;
2017-09-22 19:08:02 +02:00
2017-12-10 01:27:56 +01:00
if ( Header - > PixelsWritten = = Header - > PixelsRead )
return ;
2017-09-22 19:08:02 +02:00
int Width = Header - > Width ;
int Height = Header - > Height ;
2017-12-10 01:27:56 +01:00
int PixelsWritten = Header - > PixelsWritten ;
2017-09-22 19:08:02 +02:00
2017-12-10 01:27:56 +01: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 ;
}
}
2017-12-10 01:27:56 +01:00
Header - > PixelsRead = PixelsWritten ;
2017-09-22 19:08:02 +02:00
2019-03-19 23:08:03 +01:00
ui - > RenderProgress - > setMaximum ( mImage . width ( ) * mImage . height ( ) ) ;
ui - > RenderProgress - > setValue ( int ( Header - > PixelsRead ) ) ;
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
if ( PixelsWritten = = Width * Height )
2019-03-08 12:42:36 +01:00
ShowResult ( ) ;
# endif
}
2017-12-27 22:55:37 +01:00
2019-03-10 01:38:54 +01:00
void lcRenderDialog : : ShowResult ( )
{
2019-03-08 12:42:36 +01:00
ReadStdErr ( ) ;
ui - > RenderProgress - > setValue ( ui - > RenderProgress - > maximum ( ) ) ;
2019-03-19 23:08:03 +01:00
bool Error = ( mProcess - > exitStatus ( ) ! = QProcess : : NormalExit | | mProcess - > exitCode ( ) ! = 0 ) ;
if ( Error )
2019-03-10 01:38:54 +01:00
{
2019-03-19 23:08:03 +01:00
WriteStdLog ( Error ) ;
2019-03-08 12:42:36 +01:00
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 ( " " ) ) ;
2019-03-08 12:42:36 +01:00
error . exec ( ) ;
return ;
}
2017-12-27 22:55:37 +01:00
2019-03-08 12:42:36 +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
2019-03-08 12:42:36 +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
}
2019-03-19 23:08:03 +01:00
WriteStdLog ( ) ;
}
void lcRenderDialog : : WriteStdLog ( bool Error ) {
QFile LogFile ( QDir : : toNativeSeparators (
QFileInfo ( lcGetActiveProject ( ) - > GetFileName ( ) ) . absolutePath ( ) + " / " +
( Error ? " stderr-povrayrender " : " stdout-povrayrender " ) ) ) ;
if ( LogFile . open ( QFile : : WriteOnly | QIODevice : : Truncate | QFile : : Text ) ) {
QTextStream out ( & LogFile ) ;
foreach ( QString line , mStdErrList ) {
out < < line ;
}
LogFile . close ( ) ;
} else {
QMessageBox : : information ( this , tr ( " Error " ) , tr ( " Error writing to %1 file '%2': \n %3 " )
. arg ( Error ? " stderr " : " stdout " ) . arg ( LogFile . fileName ( ) , LogFile . errorString ( ) ) ) ;
}
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 ) ) ;
}