Пример #1
0
/******************************************************************************
* 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;
}