diff options
Diffstat (limited to 'kpovmodeler/pmpovrayrenderwidget.cpp')
-rw-r--r-- | kpovmodeler/pmpovrayrenderwidget.cpp | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/kpovmodeler/pmpovrayrenderwidget.cpp b/kpovmodeler/pmpovrayrenderwidget.cpp new file mode 100644 index 00000000..3cd44f20 --- /dev/null +++ b/kpovmodeler/pmpovrayrenderwidget.cpp @@ -0,0 +1,437 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2003 by Andreas Zehender + email : zehender@kde.org +************************************************************************** + +************************************************************************** +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +**************************************************************************/ + +#include "pmpovrayrenderwidget.h" +#include "pmdefaults.h" +#include "pmdebug.h" +#include "pmdragwidget.h" + +#include <kprocess.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kconfig.h> +#include <kurl.h> +#include <ktempfile.h> +#include <qcolor.h> +#include <qpainter.h> +#include <qtextstream.h> +#include <qdragobject.h> + +#ifdef KDE_NO_COMPAT +#undef KDE_NO_COMPAT +#endif + +#include <kapplication.h> + +QString PMPovrayRenderWidget::s_povrayCommand = c_defaultPovrayCommand; +QStringList PMPovrayRenderWidget::s_libraryPaths; + +PMPovrayRenderWidget::PMPovrayRenderWidget( QWidget* parent, const char* name ) + : PMDragWidget( parent, name ) +{ + m_pProcess = 0; + m_bSuspended = false; + m_rcvHeader = false; + m_skipBytes = 0; + m_bPixmapUpToDate = false; + m_pTempFile = 0; + + setBackgroundColor( QColor( 0, 0, 0 ) ); +} + +PMPovrayRenderWidget::~PMPovrayRenderWidget( ) +{ + cleanup( ); +} + +bool PMPovrayRenderWidget::render( const QByteArray& scene, + const PMRenderMode& m, + const KURL& documentURL ) +{ + cleanup( ); + + m_povrayOutput = ""; + m_renderMode = m; + + if( !scene.data( ) ) + { + KMessageBox::sorry( this, i18n( "Can't render an empty scene.\n" ) ); + return false; + } + + // output to tmp file + m_pTempFile = new KTempFile( QString::null, ".pov" ); + QDataStream* dstr = m_pTempFile->dataStream( ); + + if( ( m_pTempFile->status( ) != 0 ) || !dstr ) + { + KMessageBox::sorry( this, i18n( "Couldn't write the scene to a temp file.\n" ) ); + return false; + } + + dstr->writeRawBytes( scene.data( ), scene.size( ) ); + m_pTempFile->close( ); + + m_pProcess = new KProcess( ); + connect( m_pProcess, SIGNAL( receivedStdout( KProcess*, char*, int ) ), + SLOT( slotPovrayImage( KProcess*, char*, int ) ) ); + connect( m_pProcess, SIGNAL( receivedStderr( KProcess*, char*, int ) ), + SLOT( slotPovrayMessage( KProcess*, char*, int ) ) ); + connect( m_pProcess, SIGNAL( processExited( KProcess* ) ), + SLOT( slotRenderingFinished( KProcess* ) ) ); + + *m_pProcess << s_povrayCommand; + + QStringList::ConstIterator it; + QStringList args = m_renderMode.commandLineSwitches( ); + for( it = args.begin( ); it != args.end( ); ++it ) + *m_pProcess << *it; + + for( it = s_libraryPaths.begin( ); it != s_libraryPaths.end( ); ++it ) + { + QString path = *it; + if( path != QString( "/" ) ) + if( path.right( 1 ) == QString( "/" ) ) + path.truncate( path.length( ) - 1 ); + *m_pProcess << ( QString( "+L" ) + path ); + } + *m_pProcess << QString( "+I" ) + m_pTempFile->name( ) << "+O-" << "+FT" + << "+K0.0" << "+KFI1" << "+KFF1" << "+KI0.0" << "+KF0.0" + << "+SF1" << "+EF1" << "-KC" << "-D"; + +#if ( ( KDE_VERSION_MAJOR == 2 ) && ( KDE_VERSION_MINOR >= 9 ) ) || ( KDE_VERSION_MAJOR == 3 ) + if( !documentURL.isEmpty( ) && documentURL.isLocalFile( ) ) + m_pProcess->setWorkingDirectory( documentURL.directory( ) ); +#endif + + m_rcvHeader = true; + m_rcvHeaderBytes = 0; + m_rcvPixels = 0; + m_progress = 0; + m_numRestBytes = 0; + m_line = 0; + m_column = 0; + m_skipBytes = 0; + + int width = m_renderMode.width( ); + int height = m_renderMode.height( ); + + m_image.create( width, height, 32 ); + m_image.setAlphaBuffer( m_renderMode.alpha( ) ); + m_image.fill( qRgb( 0, 0, 0 ) ); + m_bPixmapUpToDate = false; + repaint( ); + + if( !m_pProcess->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( this, i18n( "Couldn't call povray.\n" + "Please check your installation " + "or set another povray command." ) ); + delete m_pProcess; + m_pProcess = 0; + return false; + } + + m_bSuspended = false; + return true; +} + +void PMPovrayRenderWidget::killRendering( ) +{ + if( m_pProcess ) + { + if( m_bSuspended ) + m_pProcess->kill( SIGCONT ); + m_bSuspended = false; + m_pProcess->kill( ); + } +} + +void PMPovrayRenderWidget::suspendRendering( ) +{ + if( m_pProcess ) + { + m_bSuspended = true; + m_pProcess->kill( SIGSTOP ); + } +} + +void PMPovrayRenderWidget::resumeRendering( ) +{ + if( m_pProcess ) + { + m_pProcess->kill( SIGCONT ); + m_bSuspended = false; + } +} + +void PMPovrayRenderWidget::slotPovrayMessage( KProcess*, + char* buffer, int buflen ) +{ + QString str; + str.setLatin1( buffer, buflen ); + m_povrayOutput += str; + emit povrayMessage( str ); +} + +void PMPovrayRenderWidget::slotPovrayImage( KProcess*, char* buffer, int buflen ) +{ + int index = 0; + int i; + int oldLine = m_line; + + if( m_rcvHeader ) + { + // receive targa header + while( ( m_rcvHeaderBytes < 18 ) && ( index < buflen ) ) + { + m_header[m_rcvHeaderBytes] = ( unsigned char ) buffer[index]; + m_rcvHeaderBytes++; + index++; + } + + if( m_rcvHeaderBytes == 18 ) + { + // complete targa header received + m_rcvHeader = false; + m_skipBytes = m_header[0]; // id length + m_bytespp = m_header[16] / 8; + } + } + + if( m_skipBytes > 0 ) + { + int skip = buflen - index; + if( skip > m_skipBytes ) + skip = m_skipBytes; + m_skipBytes -= skip; + index += skip; + } + + if( ( m_numRestBytes > 0 ) && ( index < buflen ) ) + { + while( ( m_numRestBytes < m_bytespp ) && ( index < buflen ) ) + { + m_restBytes[m_numRestBytes] = ( unsigned char ) buffer[index]; + index++; + m_numRestBytes++; + } + if( m_numRestBytes == m_bytespp ) + { + m_numRestBytes = 0; + + if( m_bytespp == 4 ) + setPixel( m_column, m_line, + qRgba( m_restBytes[2], m_restBytes[1], + m_restBytes[0], m_restBytes[3] ) ); + else + setPixel( m_column, m_line, + qRgb( m_restBytes[2], m_restBytes[1], m_restBytes[0] ) ); + + m_column++; + m_rcvPixels++; + if( m_column == m_renderMode.width( ) ) + { + m_column = 0; + m_line++; + } + } + } + + if( index < buflen ) + { + int num = ( buflen - index ) / m_bytespp; + for( i = 0; i < num; i++ ) + { + if( m_bytespp == 4 ) + setPixel( m_column, m_line, + qRgba( buffer[index+2], buffer[index+1], + buffer[index], buffer[index+3] ) ); + else + setPixel( m_column, m_line, + qRgb( buffer[index+2], buffer[index+1], + buffer[index] ) ); + index += m_bytespp; + + m_column++; + m_rcvPixels++; + if( m_column == m_renderMode.width( ) ) + { + m_column = 0; + m_line++; + } + } + } + + if( index < buflen ) + { + m_numRestBytes = buflen - index; + for( i = 0; i < m_numRestBytes; i++ ) + { + m_restBytes[i] = buffer[index]; + index++; + } + } + + if( m_line != oldLine ) + { + QPainter paint( this ); + int offset = 0; + if( m_renderMode.subSection( ) ) + { + double sr = m_renderMode.startRow( ); + if( sr < 1 ) + offset = ( int ) ( m_renderMode.height( ) * sr + 0.5 ); + else + offset += ( int ) sr; + } + paint.drawImage( 0, offset + oldLine, + m_image.copy( 0, offset + oldLine, m_image.width( ), offset + m_line - oldLine ) ); + + emit lineFinished( m_line - 1 ); + } + + int oldProgress = m_progress; + int numPixels = 0; + if( m_renderMode.subSection( ) ) + { + int sr = 0; + if( m_renderMode.startRow( ) < 1 ) + sr = ( int ) ( m_renderMode.height( ) * m_renderMode.startRow( ) + 0.5 ); + else + sr = ( int ) m_renderMode.startRow( ); + int er = 0; + if( m_renderMode.endRow( ) < 1 ) + er = ( int ) ( m_renderMode.height( ) * m_renderMode.endRow( ) + 0.5 ); + else + er = ( int ) m_renderMode.endRow( ); + + numPixels = m_renderMode.width( ) * ( er - sr ); + } + else + numPixels = m_renderMode.width( ) * m_renderMode.height( ); + + m_progress = m_rcvPixels * 100 / numPixels; + + if( m_progress != oldProgress ) + emit progress( m_progress ); + m_bPixmapUpToDate = false; +} + +void PMPovrayRenderWidget::setPixel( int x, int y, uint c ) +{ + if( m_renderMode.subSection( ) ) + { + double sr = m_renderMode.startRow( ); + if( sr < 1 ) + y += ( int ) ( m_renderMode.height( ) * sr + 0.5 ); + else + y += ( int ) sr; + } + + if( x >= 0 && x < m_image.width( ) && + y >= 0 && y < m_image.height( ) ) + m_image.setPixel( x, y, c ); +} + +/** +void PMPovrayRenderWidget::slotWroteStdin( KProcess* ) +{ + if( m_pProcess ) + m_pProcess->closeStdin( ); + m_data.resize( 0 ); +} +*/ + +void PMPovrayRenderWidget::slotRenderingFinished( KProcess* ) +{ + if( m_pProcess->normalExit( ) ) + emit( finished( m_pProcess->exitStatus( ) ) ); + else + emit( finished( -1000 ) ); + + cleanup( ); +} + +void PMPovrayRenderWidget::paintEvent( QPaintEvent* ev ) +{ + if( !m_bPixmapUpToDate ) + { + if( !m_image.isNull( ) ) + m_pixmap.convertFromImage( m_image ); + m_bPixmapUpToDate = true; + } + bitBlt( this, ev->rect( ).left( ), ev->rect( ).top( ), + &m_pixmap, ev->rect( ).left( ), ev->rect( ).top( ), + ev->rect( ).width( ), ev->rect( ).height( ), CopyROP ); +} + +void PMPovrayRenderWidget::cleanup( ) +{ + if( m_pProcess ) + delete m_pProcess; + m_pProcess = 0; + if( m_pTempFile ) + { + m_pTempFile->unlink( ); + delete m_pTempFile; + } + m_pTempFile = 0; +} + +QSize PMPovrayRenderWidget::sizeHint( ) const +{ + QSize s; + if( m_image.isNull( ) ) + s = QSize( 200, 200 ); + else + s = m_image.size( ); + + return s.expandedTo( minimumSize( ) ); +} + +void PMPovrayRenderWidget::saveConfig( KConfig* cfg ) +{ + cfg->setGroup( "Povray" ); +#if ( ( KDE_VERSION_MAJOR == 3 ) && ( KDE_VERSION_MINOR <= 1 ) ) + cfg->writeEntry( "PovrayCommand", s_povrayCommand ); + cfg->writeEntry( "LibraryPaths", s_libraryPaths ); +#else + cfg->writePathEntry( "PovrayCommand", s_povrayCommand ); + cfg->writePathEntry( "LibraryPaths", s_libraryPaths ); +#endif +} + +void PMPovrayRenderWidget::restoreConfig( KConfig* cfg ) +{ + cfg->setGroup( "Povray" ); +#if ( ( KDE_VERSION_MAJOR == 3 ) && ( KDE_VERSION_MINOR <= 1 ) ) + s_povrayCommand = cfg->readEntry( "PovrayCommand", s_povrayCommand ); + s_libraryPaths = cfg->readListEntry( "LibraryPaths" ); +#else + s_povrayCommand = cfg->readPathEntry( "PovrayCommand", s_povrayCommand ); + s_libraryPaths = cfg->readPathListEntry( "LibraryPaths" ); +#endif +} + +void PMPovrayRenderWidget::startDrag( ) +{ + QImageDrag* d = new QImageDrag( m_image, this ); + d->dragCopy( ); +} + +#include "pmpovrayrenderwidget.moc" |