/****************************************************************************** * This is the high-level rendering function, which invokes the renderer to generate one or more * output images of the scene. All rendering parameters are specified in the RenderSettings object. ******************************************************************************/ bool DataSet::renderScene(RenderSettings* settings, Viewport* viewport, QSharedPointer<FrameBuffer> frameBuffer, FrameBufferWindow* frameBufferWindow) { OVITO_CHECK_OBJECT_POINTER(settings); OVITO_CHECK_OBJECT_POINTER(viewport); // If the caller did not supply a frame buffer, get the default frame buffer for the output image, or create a temporary one if necessary. if(!frameBuffer) { if(Application::instance().guiMode()) { OVITO_ASSERT(mainWindow()); frameBufferWindow = mainWindow()->frameBufferWindow(); frameBuffer = frameBufferWindow->frameBuffer(); } if(!frameBuffer) { frameBuffer.reset(new FrameBuffer(settings->outputImageWidth(), settings->outputImageHeight())); } } // Get the selected scene renderer. SceneRenderer* renderer = settings->renderer(); if(!renderer) throw Exception(tr("No renderer has been selected.")); bool wasCanceled = false; try { // Set up the frame buffer for the output image. if(frameBufferWindow && frameBufferWindow->frameBuffer() != frameBuffer) { frameBufferWindow->setFrameBuffer(frameBuffer); frameBufferWindow->resize(frameBufferWindow->sizeHint()); } if(frameBuffer->size() != QSize(settings->outputImageWidth(), settings->outputImageHeight())) { frameBuffer->setSize(QSize(settings->outputImageWidth(), settings->outputImageHeight())); frameBuffer->clear(); if(frameBufferWindow) frameBufferWindow->resize(frameBufferWindow->sizeHint()); } if(frameBufferWindow) { if(frameBufferWindow->isHidden()) { // Center frame buffer window in main window. if(frameBufferWindow->parentWidget()) { QSize s = frameBufferWindow->frameGeometry().size(); frameBufferWindow->move(frameBufferWindow->parentWidget()->geometry().center() - QPoint(s.width() / 2, s.height() / 2)); } frameBufferWindow->show(); } frameBufferWindow->activateWindow(); } // Show progress dialog. std::unique_ptr<QProgressDialog> progressDialog; if(Application::instance().guiMode()) { progressDialog.reset(new QProgressDialog(frameBufferWindow ? (QWidget*)frameBufferWindow : (QWidget*)mainWindow())); progressDialog->setWindowModality(Qt::WindowModal); progressDialog->setAutoClose(false); progressDialog->setAutoReset(false); progressDialog->setMinimumDuration(0); progressDialog->setValue(0); } // Don't update viewports while rendering. ViewportSuspender noVPUpdates(this); // Initialize the renderer. if(renderer->startRender(this, settings)) { VideoEncoder* videoEncoder = nullptr; #ifdef OVITO_VIDEO_OUTPUT_SUPPORT QScopedPointer<VideoEncoder> videoEncoderPtr; // Initialize video encoder. if(settings->saveToFile() && settings->imageInfo().isMovie()) { if(settings->imageFilename().isEmpty()) throw Exception(tr("Cannot save rendered images to movie file. Output filename has not been specified.")); videoEncoderPtr.reset(new VideoEncoder()); videoEncoder = videoEncoderPtr.data(); videoEncoder->openFile(settings->imageFilename(), settings->outputImageWidth(), settings->outputImageHeight(), animationSettings()->framesPerSecond()); } #endif if(settings->renderingRangeType() == RenderSettings::CURRENT_FRAME) { // Render a single frame. TimePoint renderTime = animationSettings()->time(); int frameNumber = animationSettings()->timeToFrame(renderTime); if(frameBufferWindow) frameBufferWindow->setWindowTitle(tr("Frame %1").arg(frameNumber)); if(!renderFrame(renderTime, frameNumber, settings, renderer, viewport, frameBuffer.data(), videoEncoder, progressDialog.get())) wasCanceled = true; } else if(settings->renderingRangeType() == RenderSettings::ANIMATION_INTERVAL || settings->renderingRangeType() == RenderSettings::CUSTOM_INTERVAL) { // Render an animation interval. TimePoint renderTime; int firstFrameNumber, numberOfFrames; if(settings->renderingRangeType() == RenderSettings::ANIMATION_INTERVAL) { renderTime = animationSettings()->animationInterval().start(); firstFrameNumber = animationSettings()->timeToFrame(animationSettings()->animationInterval().start()); numberOfFrames = (animationSettings()->timeToFrame(animationSettings()->animationInterval().end()) - firstFrameNumber + 1); } else { firstFrameNumber = settings->customRangeStart(); renderTime = animationSettings()->frameToTime(firstFrameNumber); numberOfFrames = (settings->customRangeEnd() - firstFrameNumber + 1); } numberOfFrames = (numberOfFrames + settings->everyNthFrame() - 1) / settings->everyNthFrame(); if(numberOfFrames < 1) throw Exception(tr("Invalid rendering range: Frame %1 to %2").arg(settings->customRangeStart()).arg(settings->customRangeEnd())); if(progressDialog) progressDialog->setMaximum(numberOfFrames); // Render frames, one by one. for(int frameIndex = 0; frameIndex < numberOfFrames; frameIndex++) { if(progressDialog) progressDialog->setValue(frameIndex); int frameNumber = firstFrameNumber + frameIndex * settings->everyNthFrame() + settings->fileNumberBase(); if(frameBufferWindow) frameBufferWindow->setWindowTitle(tr("Frame %1").arg(animationSettings()->timeToFrame(renderTime))); if(!renderFrame(renderTime, frameNumber, settings, renderer, viewport, frameBuffer.data(), videoEncoder, progressDialog.get())) { wasCanceled = true; break; } if(progressDialog && progressDialog->wasCanceled()) break; // Go to next animation frame. renderTime += animationSettings()->ticksPerFrame() * settings->everyNthFrame(); } } #ifdef OVITO_VIDEO_OUTPUT_SUPPORT // Finalize movie file. if(videoEncoder) videoEncoder->closeFile(); #endif } // Shutdown renderer. renderer->endRender(); if(progressDialog && progressDialog->wasCanceled()) wasCanceled = true; } catch(...) { // Shutdown renderer. renderer->endRender(); throw; } return !wasCanceled; }