void
ViewerDisplayScheduler::timelineGoTo(TimeValue time)
{
    ViewerNodePtr isViewer = getOutputNode()->isEffectViewerNode();
    assert(isViewer);
    isViewer->getTimeline()->seekFrame(time, true, isViewer, eTimelineChangeReasonPlaybackSeek);
}
Example #2
0
ViewerTab::~ViewerTab()
{
    Gui* gui = getGui();
    if (gui) {
        NodeGraph* graph = 0;
        ViewerNodePtr internalNode = getInternalNode();

        ViewerInstancePtr viewerNode = internalNode ? internalNode->getInternalViewerNode() : ViewerInstancePtr();
        if (viewerNode) {
            NodeCollectionPtr collection = viewerNode->getNode()->getGroup();
            if (collection) {
                NodeGroupPtr isGrp = toNodeGroup(collection);
                if (isGrp) {
                    NodeGraphI* graph_i = isGrp->getNodeGraph();
                    if (graph_i) {
                        graph = dynamic_cast<NodeGraph*>(graph_i);
                        assert(graph);
                    }
                } else {
                    graph = gui->getNodeGraph();
                }
            }
            internalNode->invalidateUiContext();
        } else {
            graph = gui->getNodeGraph();
        }
        assert(graph);
        GuiAppInstancePtr app = gui->getApp();
        if ( app && !app->isClosing() && graph && (graph->getLastSelectedViewer() == this) ) {
            graph->setLastSelectedViewer(0);
        }
    }
    _imp->nodesContext.clear();
}
Example #3
0
void
ViewerGL::Implementation::activateShaderRGB(int texIndex)
{
    // always running in the main thread
    assert( qApp && qApp->thread() == QThread::currentThread() );

    // we assume that:
    // - 8-bits textures are stored non-linear and must be displayer as is
    // - floating-point textures are linear and must be decompressed according to the given lut

    if ( !shaderRGB->bind() ) {
        qDebug() << "Error when binding shader" << qPrintable( shaderRGB->log() );
    }

    ViewerNodePtr node = _this->getInternalNode();

    double gain = node->getGain();
    double gamma = node->getGamma();

    shaderRGB->setUniformValue("Tex", 0);
    shaderRGB->setUniformValue("gain", (float)gain);
    shaderRGB->setUniformValue("offset", (float)displayTextures[texIndex].offset);
    shaderRGB->setUniformValue("lut", (GLint)displayingImageLut);
    shaderRGB->setUniformValue("gamma", (float)gamma);
}
Example #4
0
void
ViewerTab::connectToBInput(int inputNb)
{
    ViewerNodePtr internalNode = getInternalNode();
    if (internalNode) {
        internalNode->connectInputToIndex(inputNb, 1);
    }
}
Example #5
0
void
ViewerTab::updateZoomComboBox(int value)
{
    assert(value > 0);
    QString str = QString::number(value);
    str.append( QLatin1Char('%') );
    ViewerNodePtr internalNode = getInternalNode();
    if (internalNode) {
        internalNode->setZoomComboBoxText(str.toStdString());
    }
}
void
ViewerDisplayScheduler::onRenderFailed(ActionRetCodeEnum status)
{
    // Upon failure clear the viewer to black. The node that failed should have posted a persistent message.
    if (status == eActionStatusAborted) {
        // When aborted, do not clear the viewer
        return;
    }

    ViewerNodePtr effect = getOutputNode()->isEffectViewerNode();
    effect->disconnectViewer();
}
ActionRetCodeEnum
ViewerDisplayScheduler::createFrameRenderResultsGeneric(const ViewerNodePtr& viewer,
                                                        const TreeRenderQueueProviderPtr& provider,
                                                        TimeValue time,
                                                        bool isPlayback,
                                                        const RotoStrokeItemPtr& activeDrawingStroke,
                                                        const std::vector<ViewIdx>& viewsToRender,
                                                        bool enableRenderStats,
                                                        RenderFrameResultsContainerPtr* future)
{
    // A global statistics object for this frame render if requested
    RenderStatsPtr stats;
    if (enableRenderStats) {
        stats.reset( new RenderStats(enableRenderStats) );
    }


    // Get parameters from the viewport
    bool fullFrameProcessing = viewer->isFullFrameProcessingEnabled();
    bool draftModeEnabled = viewer->getApp()->isDraftRenderEnabled();
    unsigned int mipMapLevel = getViewerMipMapLevel(viewer, draftModeEnabled, fullFrameProcessing);
    bool byPassCache = viewer->isRenderWithoutCacheEnabledAndTurnOff();
    ViewerCompositingOperatorEnum viewerBlend = viewer->getCurrentOperator();
    bool viewerBEqualsViewerA = viewer->getCurrentAInput() == viewer->getCurrentBInput();

    // Create the global results object
    ViewerRenderFrameResultsContainerPtr results(new  ViewerRenderFrameResultsContainer(provider));
    *future = results;
    results->time = time;
    results->recenterViewer = viewer->getViewerCenterPoint(&results->viewerCenter);

    std::list<RectD> rois;
    if (!viewer->isDoingPartialUpdates()) {
        rois.push_back(RectD());
    } else {

        // If the viewer is doing partial updates (i.e: during tracking we only update the markers areas)
        // Then we launch multiple renders over the partial areas
        std::list<RectD> partialUpdates = viewer->getPartialUpdateRects();
        for (std::list<RectD>::const_iterator it = partialUpdates.begin(); it != partialUpdates.end(); ++it) {
            if (!it->isNull()) {
                rois.push_back(*it);
            }
        }
    }

    for (std::list<RectD>::const_iterator it = rois.begin(); it != rois.end(); ++it) {
        // Render all requested views
        for (std::size_t view_i = 0; view_i < viewsToRender.size(); ++view_i) {
            ActionRetCodeEnum stat = createFrameRenderResultsForView(viewer, provider, results, viewsToRender[view_i], stats, isPlayback, it->isNull() ? 0 : &(*it), mipMapLevel, viewerBlend, byPassCache, draftModeEnabled, fullFrameProcessing, viewerBEqualsViewerA, activeDrawingStroke);
            if (isFailureRetCode(stat)) {
                return stat;
            }
        } // for each view

    }
    return eActionStatusOK;
} // createFrameRenderResultsGeneric
void
ViewerDisplayScheduler::getFrameRangeToRender(TimeValue &first,
                                              TimeValue &last) const
{
    ViewerNodePtr isViewer = getOutputNode()->isEffectViewerNode();
    ViewerNodePtr leadViewer = isViewer->getApp()->getLastViewerUsingTimeline();
    ViewerNodePtr v = leadViewer ? leadViewer : isViewer;
    assert(v);
    int left, right;
    v->getTimelineBounds(&left, &right);
    first = TimeValue(left);
    last = TimeValue(right);
}
bool
ViewerDisplayScheduler::processFramesResults(const ViewerNodePtr& viewer,const RenderFrameResultsContainerPtr& results)
{
    if ( results->frames.empty() ) {
        viewer->redrawViewer();
        return false;
    }

    ViewerRenderFrameResultsContainerPtr viewerResults = boost::dynamic_pointer_cast<ViewerRenderFrameResultsContainer>(results);
    assert(viewerResults);

    bool didSomething = false;

    for (std::list<RenderFrameSubResultPtr>::const_iterator it = viewerResults->frames.begin(); it != viewerResults->frames.end(); ++it) {
        ViewerRenderFrameSubResult* viewerObject = dynamic_cast<ViewerRenderFrameSubResult*>(it->get());
        assert(viewerObject);

        ViewerNode::UpdateViewerArgs args;
        args.time = results->time;
        args.view = (*it)->view;
        args.type = viewerObject->textureTransferType;
        args.recenterViewer = viewerResults->recenterViewer;
        args.viewerCenter = viewerResults->viewerCenter;


        for (int i = 0; i < 2; ++i) {

            const PerViewerInputRenderData& inputData = viewerObject->perInputsData[i];

            ViewerNode::UpdateViewerArgs::TextureUpload upload;
            upload.image = inputData.viewerProcessImage;
            upload.colorPickerImage = inputData.colorPickerImage;
            upload.colorPickerInputImage = inputData.colorPickerInputImage;
            upload.viewerProcessImageKey = inputData.viewerProcessImageKey;

            if (inputData.retCode == eActionStatusAborted || (inputData.retCode == eActionStatusOK && !upload.image)) {
                // If aborted or no image was rendered but the result was OK (one of the reasons could be the caller requested a RoI outside of the bounds of the image), don't transfer any texture, just redraw the viewer.
                continue;
            }
            args.viewerUploads[i].push_back(upload);
        }
        if (!args.viewerUploads[0].empty() || !args.viewerUploads[1].empty()) {
            viewer->updateViewer(args);
            didSomething = true;
        }
    }
    viewer->redrawViewer();
    return didSomething;
} // processFramesResults
NATRON_NAMESPACE_ENTER

NATRON_NAMESPACE_ANONYMOUS_ENTER

static unsigned
getViewerMipMapLevel(const ViewerNodePtr& viewer, bool draftModeEnabled, bool fullFrameProcessing)
{


    if (fullFrameProcessing) {
        return 0;
    }

    unsigned int mipMapLevel = 0;

    const double zoomFactor = viewer->getUIZoomFactor();

    int downcale_i = viewer->getDownscaleMipMapLevelKnobIndex();


    assert(downcale_i >= 0);
    if (downcale_i > 0) {
        mipMapLevel = downcale_i;
    } else {
        mipMapLevel = viewer->getMipMapLevelFromZoomFactor();
    }

    // If draft mode is enabled, compute the mipmap level according to the auto-proxy setting in the preferences
    if ( draftModeEnabled && appPTR->getCurrentSettings()->isAutoProxyEnabled() ) {
        unsigned int autoProxyLevel = appPTR->getCurrentSettings()->getAutoProxyMipMapLevel();
        if (zoomFactor > 1) {
            //Decrease draft mode at each inverse mipmaplevel level taken
            unsigned int invLevel = Image::getLevelFromScale(1. / zoomFactor);
            if (invLevel < autoProxyLevel) {
                autoProxyLevel -= invLevel;
            } else {
                autoProxyLevel = 0;
            }
        }
        mipMapLevel = (unsigned int)std::max( (int)mipMapLevel, (int)autoProxyLevel );

    }

    return mipMapLevel;
} // getViewerMipMapLevel
Example #11
0
void
ViewerTab::onTimeLineTimeChanged(SequenceTime time,
                                 int reason)
{
    Gui* gui = getGui();
    if (!gui) {
        return;
    }
    ViewerNodePtr node = _imp->viewerNode.lock();
    ViewerInstancePtr viewerNode = node->getInternalViewerNode();
    if ((TimelineChangeReasonEnum)reason != eTimelineChangeReasonPlaybackSeek) {
        node->getCurrentFrameKnob()->setValue(time, ViewSetSpec::current(), DimIdx(0), eValueChangedReasonPluginEdited);
    }

    GuiAppInstancePtr app = gui->getApp();
    if ( app &&  _imp->timeLineGui->getTimeline() != app->getTimeLine() ) {
        viewerNode->renderCurrentFrame(true);
    }
}
Example #12
0
void
ViewerTab::abortViewersAndRefresh()
{
    Gui* gui = getGui();
    if (!gui) {
        return;
    }
    const std::list<ViewerTab*> & activeNodes = gui->getViewersList();
    for (std::list<ViewerTab*>::const_iterator it = activeNodes.begin(); it != activeNodes.end(); ++it) {
        ViewerNodePtr viewer = (*it)->getInternalNode();
        if (viewer) {
            ViewerInstancePtr instance = viewer->getInternalViewerNode();
            if (instance) {
                RenderEnginePtr engine = instance->getRenderEngine();
                if ( engine ) {
                    engine->abortRenderingAutoRestart();
                    engine->renderCurrentFrame(false, true);
                }
            }
        }
    }
}
Example #13
0
bool
ViewerTab::eventFilter(QObject *target,
                       QEvent* e)
{
    if (e->type() == QEvent::MouseButtonPress) {
        Gui* gui = getGui();
        if (gui) {
            GuiAppInstancePtr app = gui->getApp();
            if (app) {
                ViewerNodePtr viewerNode = _imp->viewerNode.lock();
                if (viewerNode) {
                    NodeGuiIPtr nodegui_i = viewerNode->getNode()->getNodeGui();
                    assert(nodegui_i);
                    NodeGuiPtr nodegui = boost::dynamic_pointer_cast<NodeGui>(nodegui_i);
                    gui->selectNode(nodegui);
                }
            }
        }
    }

    return QWidget::eventFilter(target, e);
}
Example #14
0
ViewerGL::Implementation::WipePolygonEnum
ViewerGL::Implementation::getWipePolygon(const RectD & texRectClipped,
                                         bool rightPlane,
                                         QPolygonF * polygonPoints) const
{
    ///Compute a second point on the plane separator line
    ///we don't really care how far it is from the center point, it just has to be on the line
    ViewerNodePtr node = _this->getViewerTab()->getInternalNode();
    QPointF center = node->getWipeCenter();
    double angle = node->getWipeAngle();


    ///extrapolate the line to the maximum size of the RoD so we're sure the line
    ///intersection algorithm works
    double maxSize = std::max(texRectClipped.x2 - texRectClipped.x1, texRectClipped.y2 - texRectClipped.y1) * 10000.;
    double xmax, ymax;

    xmax = std::cos(angle + M_PI_2) * maxSize;
    ymax = std::sin(angle + M_PI_2) * maxSize;


    // first, compute wether the whole rectangle is on one side of the wipe
    const QPointF firstPoint ( center.x() + (rightPlane ? xmax : -xmax), center.y() + (rightPlane ? ymax : -ymax) );
    const QPointF secondPoint( center.x() + (rightPlane ? -xmax : xmax), center.y() + (rightPlane ? -ymax : ymax) );
    double crossProd11  = ( ( secondPoint.x() - center.x() ) * ( texRectClipped.y1 - center.y() )
                            - ( secondPoint.y() - center.y() ) * ( texRectClipped.x1 - center.x() ) );
    double crossProd12  = ( ( secondPoint.x() - center.x() ) * ( texRectClipped.y2 - center.y() )
                            - ( secondPoint.y() - center.y() ) * ( texRectClipped.x1 - center.x() ) );
    double crossProd21  = ( ( secondPoint.x() - center.x() ) * ( texRectClipped.y1 - center.y() )
                            - ( secondPoint.y() - center.y() ) * ( texRectClipped.x2 - center.x() ) );
    double crossProd22  = ( ( secondPoint.x() - center.x() ) * ( texRectClipped.y2 - center.y() )
                            - ( secondPoint.y() - center.y() ) * ( texRectClipped.x2 - center.x() ) );

    polygonPoints->clear();

    // if all cross products have the same sign, the rectangle is on one side
    if ( (crossProd11 >= 0) && (crossProd12 >= 0) && (crossProd21 >= 0) && (crossProd22 >= 0) ) {
        return ViewerGL::Implementation::eWipePolygonFull;
    }
    if ( (crossProd11 <= 0) && (crossProd12 <= 0) && (crossProd21 <= 0) && (crossProd22 <= 0) ) {
        return ViewerGL::Implementation::eWipePolygonEmpty;
    }

    // now go through all four corners:
    // - if the cross product is positive, the corner must be inserted
    // - if the cross-product changes sign then the intersection must be inserted
    const QLineF inter(firstPoint, secondPoint);
    if (crossProd11 >= 0) {
        *polygonPoints << QPointF(texRectClipped.x1, texRectClipped.y1);
    }
    if (crossProd11 * crossProd21 < 0) {
        QLineF e(texRectClipped.x1, texRectClipped.y1, texRectClipped.x2, texRectClipped.y1);
        QPointF p;
        QLineF::IntersectType t = inter.intersect(e, &p);
        if (t == QLineF::BoundedIntersection) {
            *polygonPoints << p;
        }
    }
    if (crossProd21 >= 0) {
        *polygonPoints << QPointF(texRectClipped.x2, texRectClipped.y1);
    }
    if (crossProd21 * crossProd22 < 0) {
        QLineF e(texRectClipped.x2, texRectClipped.y1, texRectClipped.x2, texRectClipped.y2);
        QPointF p;
        QLineF::IntersectType t = inter.intersect(e, &p);
        if (t == QLineF::BoundedIntersection) {
            *polygonPoints << p;
        }
    }
    if (crossProd22 >= 0) {
        *polygonPoints << QPointF(texRectClipped.x2, texRectClipped.y2);
    }
    if (crossProd22 * crossProd12 < 0) {
        QLineF e(texRectClipped.x2, texRectClipped.y2, texRectClipped.x1, texRectClipped.y2);
        QPointF p;
        QLineF::IntersectType t = inter.intersect(e, &p);
        if (t == QLineF::BoundedIntersection) {
            *polygonPoints << p;
        }
    }
    if (crossProd12 >= 0) {
        *polygonPoints << QPointF(texRectClipped.x1, texRectClipped.y2);
    }
    if (crossProd12 * crossProd11 < 0) {
        QLineF e(texRectClipped.x1, texRectClipped.y2, texRectClipped.x1, texRectClipped.y1);
        QPointF p;
        QLineF::IntersectType t = inter.intersect(e, &p);
        if (t == QLineF::BoundedIntersection) {
            *polygonPoints << p;
        }
    }

    return ViewerGL::Implementation::eWipePolygonPartial;
} // getWipePolygon
Example #15
0
// 0___1___2___3
// |  /|  /|  /|
// | / | / | / |
// |/  |/  |/  |
// 4---5---6----7
// |  /|  /|  /|
// | / | / | / |
// |/  |/  |/  |
// 8---9--10--11
// |  /|  /|  /|
// | / | / | / |
// |/  |/  |/  |
// 12--13--14--15
void
ViewerGL::Implementation::drawRenderingVAO(unsigned int mipMapLevel,
                                           int textureIndex,
                                           ViewerGL::DrawPolygonModeEnum polygonMode,
                                           bool background)
{
    // always running in the main thread
    assert( qApp && qApp->thread() == QThread::currentThread() );
    assert( QGLContext::currentContext() == _this->context() );


    ///the texture rectangle in image coordinates. The values in it are multiples of tile size.
    ///
    const RectI &textureBounds = this->displayTextures[textureIndex].texture->getBounds();
    //const RectD& originalCanonicalRoI = this->displayTextures[textureIndex].originalCanonicalRoi;

    ///This is the coordinates in the image being rendered where datas are valid, this is in pixel coordinates
    ///at the time we initialize it but we will convert it later to canonical coordinates. See 1)
    const double par = this->displayTextures[textureIndex].pixelAspectRatio;

    RectD canonicalRoIRoundedToTileSize;
    textureBounds.toCanonical_noClipping(mipMapLevel, par /*, rod*/, &canonicalRoIRoundedToTileSize);

    ///the RoD of the image in canonical coords.
    RectD rod = _this->getRoD(textureIndex);

    ViewerNodePtr internalNode = _this->getViewerTab()->getInternalNode();
    bool clipToDisplayWindow = internalNode->isClipToFormatEnabled();

    RectD rectClippedToRoI(canonicalRoIRoundedToTileSize);
    rectClippedToRoI.intersect(rod, &rectClippedToRoI);


    if (clipToDisplayWindow) {
        rod.intersect(this->displayTextures[textureIndex].format, &rod);
        rectClippedToRoI.intersect(this->displayTextures[textureIndex].format, &rectClippedToRoI);
    }

    


    //if user RoI is enabled, clip the rod to that roi
    bool userRoiEnabled = internalNode->isUserRoIEnabled();



    ////The texture real size (r.w,r.h) might be slightly bigger than the actual
    ////pixel coordinates bounds r.x1,r.x2 r.y1 r.y2 because we clipped these bounds against the bounds
    ////in the ViewerInstance::renderViewer function. That means we need to draw actually only the part of
    ////the texture that contains the bounds.
    ////Notice that r.w and r.h are scaled to the closest Po2 of the current scaling factor, so we need to scale it up
    ////So it is in the same coordinates as the bounds.
    ///Edit: we no longer divide by the closestPo2 since the viewer now computes images at lower resolution by itself, the drawing
    ///doesn't need to be scaled.

    if (userRoiEnabled) {
        RectD userRoI = internalNode->getUserRoI();
        //if the userRoI isn't intersecting the rod, just don't render anything
        if ( !rod.intersect(userRoI, &rod) ) {
            return;
        }

        rectClippedToRoI.intersect(rod, &rectClippedToRoI);
        //clipTexCoords<RectD>(canonicalTexRect,rectClippedToRoI,texBottom,texTop,texLeft,texRight);
    }

    if (polygonMode != eDrawPolygonModeWhole) {
        /// draw only  the plane defined by the wipe handle
        QPolygonF polygonPoints, polygonTexCoords;
        RectD floatRectClippedToRoI;
        floatRectClippedToRoI.x1 = rectClippedToRoI.x1;
        floatRectClippedToRoI.y1 = rectClippedToRoI.y1;
        floatRectClippedToRoI.x2 = rectClippedToRoI.x2;
        floatRectClippedToRoI.y2 = rectClippedToRoI.y2;
        Implementation::WipePolygonEnum polyType = this->getWipePolygon(floatRectClippedToRoI, polygonMode == eDrawPolygonModeWipeRight, &polygonPoints);

        if (polyType == Implementation::eWipePolygonEmpty) {
            ///don't draw anything
            return;
        } else if (polyType == Implementation::eWipePolygonPartial) {
            this->getPolygonTextureCoordinates(polygonPoints, canonicalRoIRoundedToTileSize, polygonTexCoords);

            assert(displayTextures[textureIndex].texture);
            GL_GPU::ActiveTexture(GL_TEXTURE0);
            GL_GPU::GetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&prevBoundTexture);
            GL_GPU::BindTexture( GL_TEXTURE_2D, displayTextures[textureIndex].texture->getTexID() );

            GL_GPU::Begin(GL_POLYGON);
            for (int i = 0; i < polygonTexCoords.size(); ++i) {
                const QPointF & tCoord = polygonTexCoords[i];
                const QPointF & vCoord = polygonPoints[i];
                GL_GPU::TexCoord2d( tCoord.x(), tCoord.y() );
                GL_GPU::Vertex2d( vCoord.x(), vCoord.y() );
            }
            GL_GPU::End();

            GL_GPU::BindTexture( GL_TEXTURE_2D, prevBoundTexture);

        } else {
            ///draw the all polygon as usual
            polygonMode = eDrawPolygonModeWhole;
        }
    }

    if (polygonMode == eDrawPolygonModeWhole) {
        const double pixelCenterOffset = 0.5;
        // draw vertices at the center of the first and last pixel in the texture, with the same texture coordinates
        rectClippedToRoI.x1 += pixelCenterOffset * par;
        rectClippedToRoI.x2 -= pixelCenterOffset * par;
        rectClippedToRoI.y1 += pixelCenterOffset;
        rectClippedToRoI.y2 -= pixelCenterOffset;
        ///Vertices are in canonical coords
        GLfloat vertices[32] = {
            (GLfloat)rod.left(),                                (GLfloat)rod.top(),    //0
            (GLfloat)(rectClippedToRoI.x1 + pixelCenterOffset), (GLfloat)rod.top(),          //1
            (GLfloat)(rectClippedToRoI.x2 - pixelCenterOffset), (GLfloat)rod.top(),    //2
            (GLfloat)rod.right(),                               (GLfloat)rod.top(),   //3
            (GLfloat)rod.left(),                                (GLfloat)(rectClippedToRoI.y2 - pixelCenterOffset), //4
            (GLfloat)rectClippedToRoI.x1,                       (GLfloat)rectClippedToRoI.y2,       //5
            (GLfloat)rectClippedToRoI.x2,                       (GLfloat)rectClippedToRoI.y2, //6
            (GLfloat)rod.right(),                               (GLfloat)rectClippedToRoI.y2, //7
            (GLfloat)rod.left(),                                (GLfloat)rectClippedToRoI.y1,        //8
            (GLfloat)rectClippedToRoI.x1,                       (GLfloat)rectClippedToRoI.y1,             //9
            (GLfloat)rectClippedToRoI.x2,                       (GLfloat)rectClippedToRoI.y1,       //10
            (GLfloat)rod.right(),                               (GLfloat)rectClippedToRoI.y1,       //11
            (GLfloat)rod.left(),                                (GLfloat)rod.bottom(), //12
            (GLfloat)rectClippedToRoI.x1,                       (GLfloat)rod.bottom(),       //13
            (GLfloat)rectClippedToRoI.x2,                       (GLfloat)rod.bottom(), //14
            (GLfloat)rod.right(),                               (GLfloat)rod.bottom() //15
        };


        GLfloat texBottom = (GLfloat)(rectClippedToRoI.y1 - canonicalRoIRoundedToTileSize.y1)  / canonicalRoIRoundedToTileSize.height();
        GLfloat texTop = (GLfloat)(rectClippedToRoI.y2 - canonicalRoIRoundedToTileSize.y1)  / canonicalRoIRoundedToTileSize.height();
        GLfloat texLeft = (GLfloat)(rectClippedToRoI.x1 - canonicalRoIRoundedToTileSize.x1)  / canonicalRoIRoundedToTileSize.width();
        GLfloat texRight = (GLfloat)(rectClippedToRoI.x2 - canonicalRoIRoundedToTileSize.x1)  / canonicalRoIRoundedToTileSize.width();
        GLfloat renderingTextureCoordinates[32] = {
            texLeft, texTop,   //0
            texLeft, texTop,   //1
            texRight, texTop,  //2
            texRight, texTop,   //3
            texLeft, texTop,   //4
            texLeft, texTop,   //5
            texRight, texTop,   //6
            texRight, texTop,   //7
            texLeft, texBottom,   //8
            texLeft, texBottom,   //9
            texRight, texBottom,    //10
            texRight, texBottom,   //11
            texLeft, texBottom,   // 12
            texLeft, texBottom,   //13
            texRight, texBottom,   //14
            texRight, texBottom    //15
        };


        if ( background && internalNode->isCheckerboardEnabled() && (polygonMode != eDrawPolygonModeWipeRight) ) {
            bool isblend = GL_GPU::IsEnabled(GL_BLEND);
            if (isblend) {
                GL_GPU::Disable(GL_BLEND);
            }
            this->drawCheckerboardTexture(rod);
            if (isblend) {
                GL_GPU::Enable(GL_BLEND);
            }
        }

        assert(displayTextures[textureIndex].texture);
        GL_GPU::ActiveTexture(GL_TEXTURE0);
        GL_GPU::GetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&prevBoundTexture);
        GL_GPU::BindTexture( GL_TEXTURE_2D, displayTextures[textureIndex].texture->getTexID() );
        glCheckError(GL_GPU);

        GL_GPU::BindBuffer(GL_ARRAY_BUFFER, this->vboVerticesId);
        GL_GPU::BufferSubData(GL_ARRAY_BUFFER, 0, 32 * sizeof(GLfloat), vertices);
        GL_GPU::EnableClientState(GL_VERTEX_ARRAY);
        GL_GPU::VertexPointer(2, GL_FLOAT, 0, 0);

        GL_GPU::BindBuffer(GL_ARRAY_BUFFER, this->vboTexturesId);
        GL_GPU::BufferSubData(GL_ARRAY_BUFFER, 0, 32 * sizeof(GLfloat), renderingTextureCoordinates);
        GL_GPU::ClientActiveTexture(GL_TEXTURE0);
        GL_GPU::EnableClientState(GL_TEXTURE_COORD_ARRAY);
        GL_GPU::TexCoordPointer(2, GL_FLOAT, 0, 0);

        GL_GPU::DisableClientState(GL_COLOR_ARRAY);

        GL_GPU::BindBuffer(GL_ARRAY_BUFFER, 0);

        GL_GPU::BindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->iboTriangleStripId);
        GL_GPU::DrawElements(GL_TRIANGLE_STRIP, 28, GL_UNSIGNED_BYTE, 0);
        glCheckErrorIgnoreOSXBug(GL_GPU);

        GL_GPU::BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        GL_GPU::DisableClientState(GL_VERTEX_ARRAY);
        GL_GPU::DisableClientState(GL_TEXTURE_COORD_ARRAY);
        GL_GPU::BindTexture( GL_TEXTURE_2D, prevBoundTexture);
        glCheckError(GL_GPU);

    }
} // drawRenderingVAO
Example #16
0
void
Gui::removeViewerTab(ViewerTab* tab,
                     bool initiatedFromNode,
                     bool deleteData)
{
    assert(tab);
    unregisterTab(tab);

    if (tab == _imp->_activeViewer) {
        _imp->_activeViewer = 0;
    }
    NodeGraph* graph = 0;
    NodeGroupPtr isGrp;
    NodeCollectionPtr collection;
    if ( tab->getInternalNode() && tab->getInternalNode()->getNode() ) {
        NodeCollectionPtr collection = tab->getInternalNode()->getNode()->getGroup();
        isGrp = toNodeGroup(collection);
    }


    if (isGrp) {
        NodeGraphI* graph_i = isGrp->getNodeGraph();
        assert(graph_i);
        graph = dynamic_cast<NodeGraph*>(graph_i);
    } else {
        graph = getNodeGraph();
    }
    assert(graph);
    if (!graph) {
        throw std::logic_error("");
    }

    ViewerTab* lastSelectedViewer = graph->getLastSelectedViewer();

    if (lastSelectedViewer == tab) {
        bool foundOne = false;
        NodesList nodes;
        if (collection) {
            nodes = collection->getNodes();
        }
        for (NodesList::iterator it = nodes.begin(); it != nodes.end(); ++it) {
            ViewerNodePtr isViewer = (*it)->isEffectViewerNode();
            if ( !isViewer || ( isViewer == tab->getInternalNode() ) || !(*it)->isActivated() ) {
                continue;
            }
            OpenGLViewerI* viewerI = isViewer->getUiContext();
            assert(viewerI);
            ViewerGL* glViewer = dynamic_cast<ViewerGL*>(viewerI);
            assert(glViewer);
            if (glViewer) {
                graph->setLastSelectedViewer( glViewer->getViewerTab() );
            }
            foundOne = true;
            break;
        }
        if (!foundOne) {
            graph->setLastSelectedViewer(0);
        }
    }

    ViewerNodePtr viewerNode = tab->getInternalNode();
    ViewerInstancePtr internalViewer;
    if (viewerNode) {
        internalViewer = viewerNode->getInternalViewerNode();
    }
    if (internalViewer) {
        internalViewer->abortAnyEvaluation();
        if (getApp()->getLastViewerUsingTimeline() == internalViewer) {
            getApp()->discardLastViewerUsingTimeline();
        }
    }

    if (!initiatedFromNode) {
        assert(_imp->_nodeGraphArea);
        ///call the deleteNode which will call this function again when the node will be deactivated.
        NodePtr internalNode = tab->getInternalNode()->getNode();
        NodeGuiIPtr guiI = internalNode->getNodeGui();
        NodeGuiPtr gui = boost::dynamic_pointer_cast<NodeGui>(guiI);
        assert(gui);
        NodeGraphI* graph_i = internalNode->getGroup()->getNodeGraph();
        assert(graph_i);
        NodeGraph* graph = dynamic_cast<NodeGraph*>(graph_i);
        assert(graph);
        if (graph) {
            graph->removeNode(gui);
        }
    } else {
        tab->hide();


        TabWidget* container = dynamic_cast<TabWidget*>( tab->parentWidget() );
        if (container) {
            container->removeTab(tab, false);
        }

        if (deleteData) {
            QMutexLocker l(&_imp->_viewerTabsMutex);
            std::list<ViewerTab*>::iterator it = std::find(_imp->_viewerTabs.begin(), _imp->_viewerTabs.end(), tab);
            if ( it != _imp->_viewerTabs.end() ) {
                _imp->_viewerTabs.erase(it);
            }
            tab->notifyGuiClosingPublic();
            tab->deleteLater();
        }
    }
    Q_EMIT viewersChanged();
} // Gui::removeViewerTab
Example #17
0
void
ViewerTab::keyPressEvent(QKeyEvent* e)
{
    ViewerNodePtr internalNode = getInternalNode();
    if (!internalNode || !internalNode->getNode()) {
        return;
    }
    //qDebug() << "ViewerTab::keyPressed:" << e->text() << "modifiers:" << e->modifiers();
    Gui* gui = getGui();
    if (gui) {
        gui->setActiveViewer(this);
    }

    bool accept = true;
    Qt::KeyboardModifiers modifiers = e->modifiers();
    Qt::Key key = (Qt::Key)Gui::handleNativeKeys( e->key(), e->nativeScanCode(), e->nativeVirtualKey() );
    double scale = 1. / ( 1 << _imp->viewer->getCurrentRenderScale() );

    if ( e->isAutoRepeat() && notifyOverlaysKeyRepeat(RenderScale(scale), e) ) {
        update();
    } else if ( notifyOverlaysKeyDown(RenderScale(scale), e) ) {
        update();
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerToInput1, modifiers, key) ) {
        connectToAInput(0);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerToInput2, modifiers, key) ) {
        connectToAInput(1);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerToInput3, modifiers, key) ) {
        connectToAInput(2);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerToInput4, modifiers, key) ) {
        connectToAInput(3);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerToInput5, modifiers, key) ) {
        connectToAInput(4);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerToInput6, modifiers, key) ) {
        connectToAInput(5);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerToInput7, modifiers, key) ) {
        connectToAInput(6);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerToInput8, modifiers, key) ) {
        connectToAInput(7);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerToInput9, modifiers, key) ) {
        connectToAInput(8);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerToInput10, modifiers, key) ) {
        connectToAInput(9);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerBToInput1, modifiers, key) ) {
        connectToBInput(0);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerBToInput2, modifiers, key) ) {
        connectToBInput(1);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerBToInput3, modifiers, key) ) {
        connectToBInput(2);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerBToInput4, modifiers, key) ) {
        connectToBInput(3);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerBToInput5, modifiers, key) ) {
        connectToBInput(4);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerBToInput6, modifiers, key) ) {
        connectToBInput(5);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerBToInput7, modifiers, key) ) {
        connectToBInput(6);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerBToInput8, modifiers, key) ) {
        connectToBInput(7);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerBToInput9, modifiers, key) ) {
        connectToBInput(8);
    } else if ( isKeybind(kShortcutGroupGlobal, kShortcutIDActionConnectViewerBToInput10, modifiers, key) ) {
        connectToBInput(9);
    } else if (key == Qt::Key_Escape) {
        _imp->viewer->s_selectionCleared();
        update();
    } else {
        accept = false;
    }
    if (accept) {
        takeClickFocus();
        e->accept();
    } else {
        handleUnCaughtKeyPressEvent(e);
        QWidget::keyPressEvent(e);
    }
} // keyPressEvent
Example #18
0
NATRON_NAMESPACE_ENTER


ViewerTab::ViewerTab(const std::string& scriptName,
                     const std::list<NodeGuiPtr> & existingNodesContext,
                     const std::list<NodeGuiPtr>& activePluginsContext,
                     Gui* gui,
                     const NodeGuiPtr& node_ui,
                     QWidget* parent)
    : QWidget(parent)
    , PanelWidget(scriptName, this, gui)
    , _imp( new ViewerTabPrivate(this, node_ui) )
{
    ViewerNodePtr node = node_ui->getNode()->isEffectViewerNode();
    installEventFilter(this);
    setMouseTracking(true);
    NodePtr internalNode = node->getNode();
    QObject::connect( internalNode.get(), SIGNAL(scriptNameChanged(QString)), this, SLOT(onInternalNodeScriptNameChanged(QString)) );
    QObject::connect( internalNode.get(), SIGNAL(labelChanged(QString,QString)), this, SLOT(onInternalNodeLabelChanged(QString,QString)) );
    QObject::connect( node.get(), SIGNAL(internalViewerCreated()), this, SLOT(onInternalViewerCreated()));

    _imp->mainLayout = new QVBoxLayout(this);
    setLayout(_imp->mainLayout);
    _imp->mainLayout->setSpacing(0);
    _imp->mainLayout->setContentsMargins(0, 0, 0, 0);

    QFontMetrics fm(font(), 0);


    _imp->viewerContainer = new QWidget(this);
    _imp->viewerLayout = new QHBoxLayout(_imp->viewerContainer);
    _imp->viewerLayout->setContentsMargins(0, 0, 0, 0);
    _imp->viewerLayout->setSpacing(0);

    _imp->viewerSubContainer = new QWidget(_imp->viewerContainer);
    _imp->viewerSubContainerLayout = new QVBoxLayout(_imp->viewerSubContainer);
    _imp->viewerSubContainerLayout->setContentsMargins(0, 0, 0, 0);
    _imp->viewerSubContainerLayout->setSpacing(1);


    // Info bars
    QString inputNames[2] = {
        QString::fromUtf8("A:"), QString::fromUtf8("B:")
    };

    bool infobarvisible = node->isInfoBarVisible();
    for (int i = 0; i < 2; ++i) {
        _imp->infoWidget[i] = new InfoViewerWidget(inputNames[i], this);

    }

    // Viewer
    _imp->viewer = new ViewerGL(this);

    GuiAppInstancePtr app = gui->getApp();

    // Init viewer to project format
    {
        Format projectFormat;
        app->getProject()->getProjectDefaultFormat(&projectFormat);

        RectD canonicalFormat = projectFormat.toCanonicalFormat();
        for (int i = 0; i < 2; ++i) {
            _imp->viewer->setInfoViewer(_imp->infoWidget[i], i);
            _imp->viewer->setRegionOfDefinition(canonicalFormat, projectFormat.getPixelAspectRatio(), i);
            setInfoBarAndViewerResolution(projectFormat, canonicalFormat, projectFormat.getPixelAspectRatio(), i);
        }
        _imp->viewer->resetWipeControls();
    }

    _imp->viewerSubContainerLayout->addWidget(_imp->viewer);
    for (int i = 0; i < 2; ++i) {
        _imp->viewerSubContainerLayout->addWidget(_imp->infoWidget[i]);
        _imp->viewer->setInfoViewer(_imp->infoWidget[i], i);
        if (i == 1 || !infobarvisible) {
            _imp->infoWidget[i]->hide();
        }
    }

    manageSlotsForInfoWidget(0, true);


    _imp->viewerLayout->addWidget(_imp->viewerSubContainer);
    _imp->mainLayout->addWidget(_imp->viewerContainer);

    TimeLinePtr timeline = app->getTimeLine();
    _imp->timeLineGui = new TimeLineGui(node, timeline, getGui(), this);
    QObject::connect( _imp->timeLineGui, SIGNAL(boundariesChanged(SequenceTime,SequenceTime)),
                      this, SLOT(onTimelineBoundariesChanged(SequenceTime,SequenceTime)) );
    QObject::connect( app->getProject().get(), SIGNAL(frameRangeChanged(int,int)), _imp->timeLineGui, SLOT(onProjectFrameRangeChanged(int,int)) );
    _imp->timeLineGui->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);

    if (!node->isTimelineVisible()) {
        _imp->timeLineGui->hide();
    }

    //Add some spacing because the timeline might be black as the info
    _imp->mainLayout->addSpacing( TO_DPIY(5) );
    _imp->mainLayout->addWidget(_imp->timeLineGui);

    double leftBound, rightBound;
    leftBound = node->getPlaybackInPointKnob()->getValue();
    rightBound = node->getPlaybackOutPointKnob()->getValue();

    TimeValue projectLeft, projectRight;
    app->getProject()->getFrameRange(&projectLeft, &projectRight);

    _imp->timeLineGui->setBoundaries(leftBound, rightBound);
    onTimelineBoundariesChanged(leftBound, rightBound);
    _imp->timeLineGui->setFrameRangeEdited(projectLeft != leftBound || projectRight != rightBound);;


    manageTimelineSlot(false, timeline);

    QObject::connect( node.get(), SIGNAL(renderStatsAvailable(int,double,RenderStatsMap)),
                      this, SLOT(onRenderStatsAvailable(int,double,RenderStatsMap)) );
    QObject::connect( _imp->viewer, SIGNAL(zoomChanged(int)), this, SLOT(updateZoomComboBox(int)) );
    QObject::connect( node.get(), SIGNAL(viewerDisconnected()), this, SLOT(disconnectViewer()) );


    createNodeViewerInterface(node_ui);
    setPluginViewerInterface(node_ui);
    
    for (std::list<NodeGuiPtr>::const_iterator it = existingNodesContext.begin(); it != existingNodesContext.end(); ++it) {
        ViewerNodePtr isViewerNode = (*it)->getNode()->isEffectViewerNode();
        // For viewers, create the viewer interface separately
        if (!isViewerNode) {
            createNodeViewerInterface(*it);
        }
    }
    for (std::list<NodeGuiPtr>::const_iterator it = activePluginsContext.begin(); it != activePluginsContext.end(); ++it) {
        ViewerNodePtr isViewerNode = (*it)->getNode()->isEffectViewerNode();
        // For viewers, create the viewer interface separately
        if (!isViewerNode) {
            setPluginViewerInterface(*it);
        }
    }


    setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred);

    _imp->viewerNode.lock()->setUiContext( getViewer() );

    QTimer::singleShot( 25, _imp->timeLineGui, SLOT(recenterOnBounds()) );


    //Refresh the viewport lock state
    const std::list<ViewerTab*>& viewers = getGui()->getViewersList();
    if ( !viewers.empty() ) {
        ViewerTab* other = viewers.front();
        if ( other->getInternalNode()->isViewersSynchroEnabled() ) {
            double left, bottom, factor, par;
            other->getViewer()->getProjection(&left, &bottom, &factor, &par);
            _imp->viewer->setProjection(left, bottom, factor, par);
            node->setViewersSynchroEnabled(true);
        }
    }

    _imp->cachedFramesThread.reset(new CachedFramesThread(this));
    _imp->cachedFramesThread->start();
}
TimeValue
ViewerDisplayScheduler::getLastRenderedTime() const
{
    ViewerNodePtr effect = getOutputNode()->isEffectViewerNode();
    return TimeValue(effect->getLastRenderedTime());
}
TimeValue
ViewerDisplayScheduler::timelineGetTime() const
{
    ViewerNodePtr isViewer = getOutputNode()->isEffectViewerNode();
    return TimeValue(isViewer->getTimeline()->currentFrame());
}
Example #21
0
ViewerTab*
Gui::addNewViewerTab(const NodeGuiPtr& node,
                     TabWidget* where)
{
    if (!node) {
        return 0;
    }

    ViewerNodePtr viewer = node->getNode()->isEffectViewerNode();

    NodesGuiList activeNodeViewerUi, nodeViewerUi;

    //Don't create tracker & roto interface for file dialog preview viewer
    NodeCollectionPtr group = viewer->getNode()->getGroup();
    if (group) {
        if ( !_imp->_viewerTabs.empty() ) {
            ( *_imp->_viewerTabs.begin() )->getNodesViewerInterface(&nodeViewerUi, &activeNodeViewerUi);
        } else {
            NodeGraph* graph = dynamic_cast<NodeGraph*>( group->getNodeGraph() );
            if (!graph) {
                graph = _imp->_nodeGraphArea;
            }

            if (graph) {
                const NodesGuiList & allNodes = graph->getAllActiveNodes();
                std::set<std::string> activeNodesPluginID;

                for (NodesGuiList::const_iterator it = allNodes.begin(); it != allNodes.end(); ++it) {
                    nodeViewerUi.push_back( *it );
                    std::string pluginID = (*it)->getNode()->getPluginID();
                    std::set<std::string>::iterator found = activeNodesPluginID.find(pluginID);
                    if ( found == activeNodesPluginID.end() ) {
                        activeNodesPluginID.insert(pluginID);
                        activeNodeViewerUi.push_back(*it);
                    }
                }
            }
        }
    }

    std::string nodeName =  node->getNode()->getFullyQualifiedName();
    for (std::size_t i = 0; i < nodeName.size(); ++i) {
        if (nodeName[i] == '.') {
            nodeName[i] = '_';
        }
    }
    std::string label;
    NodeGraph::makeFullyQualifiedLabel(node->getNode(), &label);

    ViewerTab* tab = new ViewerTab(nodeName, nodeViewerUi, activeNodeViewerUi, this, node, where);
    tab->setLabel(label);

    QObject::connect( tab->getViewer(), SIGNAL(imageChanged(int,bool)), this, SLOT(onViewerImageChanged(int,bool)) );
    {
        QMutexLocker l(&_imp->_viewerTabsMutex);
        _imp->_viewerTabs.push_back(tab);
        if (!_imp->_activeViewer) {
            _imp->_activeViewer = tab;
        }
    }
    where->appendTab(tab, tab);
    Q_EMIT viewersChanged();

    return tab;
} // Gui::addNewViewerTab
static ActionRetCodeEnum createFrameRenderResultsForView(const ViewerNodePtr& viewer,
                                                         const TreeRenderQueueProviderPtr& provider,
                                                         const ViewerRenderFrameResultsContainerPtr& results,
                                                         ViewIdx view,
                                                         const RenderStatsPtr& stats,
                                                         bool isPlayback,
                                                         const RectD* partialUpdateRoIParam,
                                                         unsigned int mipMapLevel,
                                                         ViewerCompositingOperatorEnum viewerBlend,
                                                         bool byPassCache,
                                                         bool draftModeEnabled,
                                                         bool fullFrameProcessing,
                                                         bool viewerBEqualsViewerA,
                                                         const RotoStrokeItemPtr& activeDrawingStroke)
{

    // Initialize for each view a sub-result.
    // Each view has 2 renders: the A and B viewerprocess
    ViewerRenderFrameSubResultPtr subResult(new ViewerRenderFrameSubResult);
    results->frames.push_back(subResult);
    subResult->view = view;
    subResult->stats = stats;

    if (partialUpdateRoIParam) {
        subResult->textureTransferType = OpenGLViewerI::TextureTransferArgs::eTextureTransferTypeOverlay;
    } else if (activeDrawingStroke && activeDrawingStroke->getRenderCloneCurrentStrokeStartPointIndex() > 0) {
        // Upon painting ticks, we just have to update the viewer for the area that was painted
        subResult->textureTransferType = OpenGLViewerI::TextureTransferArgs::eTextureTransferTypeModify;
    } else {
        subResult->textureTransferType = OpenGLViewerI::TextureTransferArgs::eTextureTransferTypeReplace;
    }

    for (int viewerInputIndex = 0; viewerInputIndex < 2; ++viewerInputIndex) {
        subResult->perInputsData[viewerInputIndex].retCode = eActionStatusFailed;
        if (viewerInputIndex == 1 && (viewerBEqualsViewerA || viewerBlend == eViewerCompositingOperatorNone)) {
            if (viewerBEqualsViewerA && viewerBlend != eViewerCompositingOperatorNone) {
                subResult->copyInputBFromA = true;
            }
            continue;
        }
        if (viewer->isViewerPaused(viewerInputIndex)) {
            subResult->perInputsData[viewerInputIndex].retCode = eActionStatusAborted;
            continue;
        }
        ViewerInstancePtr viewerProcess = viewer->getViewerProcessNode(viewerInputIndex);
        subResult->perInputsData[viewerInputIndex].viewerProcessNode = viewerProcess->getNode();



        TreeRender::CtorArgsPtr initArgs(new TreeRender::CtorArgs);
        initArgs->treeRootEffect = viewerProcess;
        initArgs->provider = provider;
        initArgs->time = results->time;
        initArgs->view = subResult->view;

        // Render by default on disk is always using a mipmap level of 0 but using the proxy scale of the project
        initArgs->mipMapLevel = mipMapLevel;


#pragma message WARN("Todo: set proxy scale here")
        initArgs->proxyScale = RenderScale(1.);

        // Render the RoD if fullframe processing
        if (partialUpdateRoIParam) {
            initArgs->canonicalRoI = *partialUpdateRoIParam;
        } else {
            RectD roi;
            if (!fullFrameProcessing) {
                roi = viewerProcess->getViewerRoI();
            }
            initArgs->canonicalRoI = roi;

        }
        
        initArgs->stats = stats;
        initArgs->activeRotoDrawableItem = activeDrawingStroke;
        initArgs->draftMode = draftModeEnabled;
        initArgs->playback = isPlayback;
        initArgs->byPassCache = byPassCache;
        initArgs->preventConcurrentTreeRenders = (activeDrawingStroke || partialUpdateRoIParam);
        if (!isPlayback && subResult->textureTransferType == OpenGLViewerI::TextureTransferArgs::eTextureTransferTypeReplace && !activeDrawingStroke) {
            subResult->perInputsData[viewerInputIndex].colorPickerNode = viewerInputIndex == 0 ? viewer->getCurrentAInput() : viewer->getCurrentBInput();
            if (subResult->perInputsData[viewerInputIndex].colorPickerNode) {
                // Also sample the "main" input of the color picker node, this is useful for keyers.
                int mainInput = subResult->perInputsData[viewerInputIndex].colorPickerNode->getPreferredInput();
                subResult->perInputsData[viewerInputIndex].colorPickerInputNode = subResult->perInputsData[viewerInputIndex].colorPickerNode->getInput(mainInput);
            }
        }
        if (subResult->perInputsData[viewerInputIndex].colorPickerNode) {
            initArgs->extraNodesToSample.push_back(subResult->perInputsData[viewerInputIndex].colorPickerNode);
        }
        if (subResult->perInputsData[viewerInputIndex].colorPickerInputImage) {
            initArgs->extraNodesToSample.push_back(subResult->perInputsData[viewerInputIndex].colorPickerInputNode);
        }

        subResult->perInputsData[viewerInputIndex].render = TreeRender::create(initArgs);
        if (!subResult->perInputsData[viewerInputIndex].render) {
            return eActionStatusFailed;
        }

    } // for each viewer input
    return eActionStatusOK;
} // createFrameRenderResultsForView