/// This is called whenever a param is changed by the plugin so that
/// the recursive instanceChangedAction will be fed the correct
/// renderScale
void
OfxImageEffectInstance::getRenderScaleRecursive(double &x,
                                                double &y) const
{
    assert( getOfxEffectInstance() );
    std::list<ViewerInstance*> attachedViewers;
    getOfxEffectInstance()->getNode()->hasViewersConnected(&attachedViewers);
    ///get the render scale of the 1st viewer
    if ( !attachedViewers.empty() ) {
        ViewerInstance* first = attachedViewers.front();
        int mipMapLevel = first->getMipMapLevel();
        x = Natron::Image::getScaleFromMipMapLevel( (unsigned int)mipMapLevel );
        y = x;
    } else {
        x = 1.;
        y = 1.;
    }
}
Пример #2
0
void ViewerCollector::deleteDeadInstances()
{
  AutoLock l(&m_lockObj);

  InstanceList::iterator iter = m_instances.begin();
  while (iter != m_instances.end()) {
    ViewerInstance *instance = *iter;
    if (instance->isStopped()) {
      if (instance->requiresReconnect()) {
        ++m_countToReconnect;
      }
      delete instance;
      iter = m_instances.erase(iter);
    } else {
      iter++;
    }
  }
}
Пример #3
0
void
NodeGraph::selectNode(const NodeGuiPtr & n,
                      bool addToSelection)
{
    if ( !n->isVisible() ) {
        return;
    }
    bool alreadyInSelection = std::find(_imp->_selection.begin(),_imp->_selection.end(),n) != _imp->_selection.end();


    assert(n);
    if (addToSelection && !alreadyInSelection) {
        _imp->_selection.push_back(n);
    } else if (!addToSelection) {
        clearSelection();
        _imp->_selection.push_back(n);
    }

    n->setUserSelected(true);

    ViewerInstance* isViewer =  n->getNode()->isEffectViewer();
    if (isViewer) {
        OpenGLViewerI* viewer = isViewer->getUiContext();
        const std::list<ViewerTab*> & viewerTabs = getGui()->getViewersList();
        for (std::list<ViewerTab*>::const_iterator it = viewerTabs.begin(); it != viewerTabs.end(); ++it) {
            if ( (*it)->getViewer() == viewer ) {
                setLastSelectedViewer( (*it) );
            }
        }
    }

    bool magnifiedNodeSelected = false;
    if (_imp->_magnifiedNode) {
        magnifiedNodeSelected = std::find(_imp->_selection.begin(),_imp->_selection.end(),_imp->_magnifiedNode)
                                != _imp->_selection.end();
    }
    if (magnifiedNodeSelected && _imp->_magnifOn) {
        _imp->_magnifOn = false;
        _imp->_magnifiedNode->setScale_natron(_imp->_nodeSelectedScaleBeforeMagnif);
    }
}
Пример #4
0
Natron::Status VideoEngine::renderFrame(SequenceTime time,bool singleThreaded) {
    /*pre process frame*/
    
//    Status stat = _tree.preProcessFrame();
//    if (stat == StatFailed) {
//        return stat;
//        //don't throw an exception here, this is regular behaviour when a mandatory input is not connected.
//        // We don't want to popup a dialog everytime it occurs
//        //      throw std::runtime_error("PreProcessFrame failed, mandatory inputs are probably not connected.");
//    }
    bool isSequentialRender = _currentRunArgs._frameRequestsCount > 1 || _currentRunArgs._frameRequestsCount == -1 ||
    _currentRunArgs._forceSequential;
    Status stat = StatOK;
    /*get the time at which we started rendering the frame*/
    gettimeofday(&_startRenderFrameTime, 0);
    if (_tree.isOutputAViewer() && !_tree.isOutputAnOpenFXNode()) {
        ViewerInstance* viewer = _tree.outputAsViewer();
        stat = viewer->renderViewer(time,singleThreaded,isSequentialRender);
        
        if (!_currentRunArgs._sameFrame) {
            QMutexLocker timerLocker(&_timerMutex);
            _timer->waitUntilNextFrameIsDue(); // timer synchronizing with the requested fps
            if ((_timerFrameCount % NATRON_FPS_REFRESH_RATE) == 0 && _currentRunArgs._frameRequestsCount == -1) {
                emit fpsChanged(_timer->actualFrameRate(),_timer->getDesiredFrameRate()); // refreshing fps display on the GUI
                _timerFrameCount = 1; //reseting to 1
            } else {
                ++_timerFrameCount;
            }
            
        }
        
        if (stat == StatFailed) {
            viewer->disconnectViewer();
        }
    
    } else {
        RenderScale scale;
        scale.x = scale.y = 1.;
        RectI rod;
        bool isProjectFormat;
        
        int viewsCount = _tree.getOutput()->getApp()->getProject()->getProjectViewsCount();
        int mainView = 0;
        if (isSequentialRender) {
            mainView = _tree.getOutput()->getApp()->getMainView();
        }
        
        for (int i = 0; i < viewsCount;++i) {
            
            if (isSequentialRender && i != mainView) {
                ///@see the warning in EffectInstance::evaluate
                continue;
            }
            // Do not catch exceptions: if an exception occurs here it is probably fatal, since
            // it comes from Natron itself. All exceptions from plugins are already caught
            // by the HostSupport library.
            stat = _tree.getOutput()->getRegionOfDefinition_public(time,scale,i, &rod,&isProjectFormat);
            if (stat != StatFailed) {
                ImageComponents components;
                ImageBitDepth imageDepth;
                _tree.getOutput()->getPreferredDepthAndComponents(-1, &components, &imageDepth);
                (void)_tree.getOutput()->renderRoI(EffectInstance::RenderRoIArgs(time, //< the time at which to render
                                                                                 scale, //< the scale at which to render
                                                                                 0, //< the mipmap level (redundant with the scale)
                                                                                 i , //< the view to render
                                                                                 rod, //< the region of interest (in pixel coordinates)
                                                                                 isSequentialRender, // is this sequential
                                                                                 false,  // is this render due to user interaction ?
                                                                                 false,//< bypass cache ?
                                                                                 &rod, // < any precomputed rod ?
                                                                                 components,
                                                                                 imageDepth));
            } else {
                break;
            }
        }
    }
//
//    if (stat == StatFailed) {
//        throw std::runtime_error("Render failed");
//    }
    return stat;

}
Пример #5
0
void VideoEngine::iterateKernel(bool singleThreaded) {
    for(;;){ // infinite loop
        
        {
            QMutexLocker locker(&_abortedRequestedMutex);
            if(_abortRequested > 0) {
                locker.unlock();
                return;
            }
        }
        
        Natron::OutputEffectInstance* output = dynamic_cast<Natron::OutputEffectInstance*>(_tree.getOutput());
        assert(output);
        ViewerInstance* viewer = dynamic_cast<ViewerInstance*>(output);
        
        /*update the tree inputs */
        _tree.refreshRenderInputs();
        
        
        if(viewer){
            if (singleThreaded || appPTR->isBackground()) {
                getFrameRange();
            } else {
                {
                    QMutexLocker l(&_abortedRequestedMutex);
                    if (_abortRequested > 0) {
                        return;
                    }
                }
                
                bool mustQuit;
                {
                    QMutexLocker l(&_mustQuitMutex);
                    mustQuit = _mustQuit;
                }
                
                QMutexLocker l(&_getFrameRangeMutex);
                _gettingFrameRange = true;
                emit mustGetFrameRange();
                while (_gettingFrameRange && !mustQuit) {
                    _getFrameRangeCond.wait(&_getFrameRangeMutex);
                }
                
            }
            
            //If the frame range is not locked, let the user define it.
            if (viewer->isFrameRangeLocked()) {
                _timeline->setFrameRange(_firstFrame, _lastFrame);
            }
        }
        
        int firstFrame,lastFrame;
        if (viewer) {
            firstFrame = _timeline->leftBound();
            lastFrame = _timeline->rightBound();
        } else {
            firstFrame = output->getFirstFrame();
            lastFrame = output->getLastFrame();
        }
        
        //////////////////////////////
        // Set the current frame
        //
        int currentFrame = 0;
        if (!_currentRunArgs._recursiveCall) {
            
            /*if writing on disk and not a recursive call, move back the timeline cursor to the start*/
            if (viewer) {
                currentFrame = _timeline->currentFrame();
            } else {
                output->setCurrentFrame(firstFrame);
                currentFrame = firstFrame;
            }
            
        } else if(!_currentRunArgs._sameFrame && _currentRunArgs._seekTimeline) {
            assert(_currentRunArgs._recursiveCall); // we're in the else part
            if (!viewer) {
                output->setCurrentFrame(output->getCurrentFrame()+1);
                currentFrame = output->getCurrentFrame();
                if(currentFrame > lastFrame){
                    return;
                }
            } else {
                // viewer
                assert(viewer);
                if (_currentRunArgs._forward) {
                    currentFrame = _timeline->currentFrame();
                    if (currentFrame < lastFrame) {
                        _timeline->incrementCurrentFrame(output);
                        ++currentFrame;
                    } else {
                        QMutexLocker loopModeLocker(&_loopModeMutex);
                        if (_loopMode) { // loop only for a viewer
                            currentFrame = firstFrame;
                            _timeline->seekFrame(currentFrame,output);
                        } else {
                            loopModeLocker.unlock();
                            return;
                        }
                    }
                    
                } else {
                    currentFrame = _timeline->currentFrame();
                    if (currentFrame > firstFrame) {
                        _timeline->decrementCurrentFrame(output);
                        --currentFrame;
                    } else {
                        QMutexLocker loopModeLocker(&_loopModeMutex);
                        if (_loopMode) { //loop only for a viewer
                            currentFrame = lastFrame;
                            _timeline->seekFrame(currentFrame,output);
                        } else {
                            loopModeLocker.unlock();
                            return;
                        }
                    }
                }
            }
        }
        
        ///////////////////////////////
        // Check whether we need to stop the engine or not for various reasons.
        //
        {
            QMutexLocker locker(&_abortedRequestedMutex);
            if(_abortRequested > 0 || // #1 aborted by the user
               
               (_tree.isOutputAViewer() // #2 the Tree contains only 1 frame and we rendered it
                &&  _currentRunArgs._recursiveCall
                &&  firstFrame == lastFrame
                && _currentRunArgs._frameRequestsCount == -1
                && _currentRunArgs._frameRequestIndex == 1)
               
               || _currentRunArgs._frameRequestsCount == 0// #3 the sequence ended and it was not an infinite run
               || (appPTR->getAppType() == AppManager::APP_BACKGROUND_AUTO_RUN && appPTR->hasAbortAnyProcessingBeenCalled()))
            {
                return;
            }
        }
        
        ///before rendering the frame, clear any persistent message that may be left
        _tree.clearPersistentMessages();
        
        ////////////////////////
        // Render currentFrame
        //
        // if the output is a writer, _tree.outputAsWriter() returns a valid pointer/
        Status stat;
        try {
            stat =  renderFrame(currentFrame,singleThreaded);
        } catch (const std::exception &e) {
            std::stringstream ss;
            ss << "Error while rendering" << " frame " << currentFrame << ": " << e.what();
            if (viewer) {
                //viewer->setPersistentMessage(Natron::ERROR_MESSAGE, ss.str());
                viewer->disconnectViewer();
            } else {
                std::cout << ss.str() << std::endl;
            }
            return;
            
        }
        
        if (stat == StatFailed) {
            return;
        }
        
        
        /*The frame has been rendered , we call engineLoop() which will reset all the flags,
         update viewers
         and appropriately increment counters for the next frame in the sequence.*/
        emit frameRendered(currentFrame);
        if(appPTR->isBackground()){
            QString frameStr = QString::number(currentFrame);
            appPTR->writeToOutputPipe(kFrameRenderedStringLong + frameStr,kFrameRenderedStringShort + frameStr);
        }
        
        if (singleThreaded) {
            QCoreApplication::processEvents();
            
            ///if single threaded: the user might have requested to exit and the engine might be deleted after the events process.
            if (_mustQuit) {
                return;
            }
        }
        
        if(_currentRunArgs._frameRequestIndex == 0 && _currentRunArgs._frameRequestsCount == 1 && !_currentRunArgs._sameFrame){
            _currentRunArgs._frameRequestsCount = 0;
        }else if(_currentRunArgs._frameRequestsCount!=-1){ // if the frameRequestCount is defined (i.e: not indefinitely running)
            --_currentRunArgs._frameRequestsCount;
        }
        ++_currentRunArgs._frameRequestIndex;//incrementing the frame counter
        
        _currentRunArgs._recursiveCall = true;
    } // end for(;;)
}
void
ProjectGuiSerialization::initialize(const ProjectGui* projectGui)
{
    NodesList activeNodes;

    projectGui->getInternalProject()->getActiveNodesExpandGroups(&activeNodes);

    _serializedNodes.clear();
    for (NodesList::iterator it = activeNodes.begin(); it != activeNodes.end(); ++it) {
        boost::shared_ptr<NodeGuiI> nodegui_i = (*it)->getNodeGui();
        if (!nodegui_i) {
            continue;
        }
        NodeGuiPtr nodegui = boost::dynamic_pointer_cast<NodeGui>(nodegui_i);

        if ( nodegui->isVisible() ) {
            boost::shared_ptr<NodeCollection> isInCollection = (*it)->getGroup();
            NodeGroup* isCollectionAGroup = dynamic_cast<NodeGroup*>( isInCollection.get() );
            if (!isCollectionAGroup) {
                ///Nodes within a group will be serialized recursively in the node group serialization
                NodeGuiSerialization state;
                nodegui->serialize(&state);
                _serializedNodes.push_back(state);
            }
            ViewerInstance* viewer = (*it)->isEffectViewer();
            if (viewer) {
                ViewerTab* tab = projectGui->getGui()->getViewerTabForInstance(viewer);
                assert(tab);
                ViewerData viewerData;
                double zoompar;
                tab->getViewer()->getProjection(&viewerData.zoomLeft, &viewerData.zoomBottom, &viewerData.zoomFactor, &zoompar);
                viewerData.userRoI = tab->getViewer()->getUserRegionOfInterest();
                viewerData.userRoIenabled = tab->getViewer()->isUserRegionOfInterestEnabled();
                viewerData.isClippedToProject = tab->isClippedToProject();
                viewerData.autoContrastEnabled = tab->isAutoContrastEnabled();
                viewerData.gain = tab->getGain();
                viewerData.gamma = tab->getGamma();
                viewerData.colorSpace = tab->getColorSpace();
                viewerData.channels = tab->getChannelsString();
                viewerData.renderScaleActivated = tab->getRenderScaleActivated();
                viewerData.mipMapLevel = tab->getMipMapLevel();
                viewerData.zoomOrPanSinceLastFit = tab->getZoomOrPannedSinceLastFit();
                viewerData.wipeCompositingOp = (int)tab->getCompositingOperator();
                viewerData.leftToolbarVisible = tab->isLeftToolbarVisible();
                viewerData.rightToolbarVisible = tab->isRightToolbarVisible();
                viewerData.topToolbarVisible = tab->isTopToolbarVisible();
                viewerData.infobarVisible = tab->isInfobarVisible();
                viewerData.playerVisible = tab->isPlayerVisible();
                viewerData.timelineVisible = tab->isTimelineVisible();
                viewerData.checkerboardEnabled = tab->isCheckerboardEnabled();
                viewerData.fps = tab->getDesiredFps();
                viewerData.fpsLocked = tab->isFPSLocked();
                viewerData.isPauseEnabled[0] = tab->isViewerPaused(0);
                viewerData.isPauseEnabled[1] = tab->isViewerPaused(1);
                viewerData.layerName = tab->getCurrentLayerName().toStdString();
                viewerData.alphaLayerName = tab->getCurrentAlphaLayerName().toStdString();
                tab->getTimelineBounds(&viewerData.leftBound, &viewerData.rightBound);
                tab->getActiveInputs(&viewerData.aChoice, &viewerData.bChoice);
                viewerData.version = VIEWER_DATA_SERIALIZATION_VERSION;
                _viewersData.insert( std::make_pair(viewer->getNode()->getScriptName_mt_safe(), viewerData) );
            }
        }
    }

    ///Init windows
    _layoutSerialization.initialize( projectGui->getGui() );

    ///save histograms
    std::list<Histogram*> histograms = projectGui->getGui()->getHistograms_mt_safe();
    for (std::list<Histogram*>::const_iterator it = histograms.begin(); it != histograms.end(); ++it) {
        _histograms.push_back( (*it)->objectName().toStdString() );
    }

    ///save opened panels by order

    std::list<DockablePanel*> panels = projectGui->getGui()->getVisiblePanels_mt_safe();
    for (std::list<DockablePanel*>::iterator it = panels.begin(); it != panels.end(); ++it) {
        if ( (*it)->isVisible() ) {
            KnobHolder* holder = (*it)->getHolder();
            assert(holder);

            EffectInstance* isEffect = dynamic_cast<EffectInstance*>(holder);
            Project* isProject = dynamic_cast<Project*>(holder);

            if (isProject) {
                _openedPanelsOrdered.push_back(kNatronProjectSettingsPanelSerializationName);
            } else if (isEffect) {
                _openedPanelsOrdered.push_back( isEffect->getNode()->getFullyQualifiedName() );
            }
        }
    }

    _scriptEditorInput = projectGui->getGui()->getScriptEditor()->getAutoSavedScript().toStdString();

    std::map<NATRON_PYTHON_NAMESPACE::PyPanel*, std::string> pythonPanels = projectGui->getGui()->getPythonPanels();
    for (std::map<NATRON_PYTHON_NAMESPACE::PyPanel*, std::string>::iterator it = pythonPanels.begin(); it != pythonPanels.end(); ++it) {
        boost::shared_ptr<PythonPanelSerialization> s(new PythonPanelSerialization);
        s->initialize(it->first, it->second);
        _pythonPanels.push_back(s);
    }
} // initialize
void ProjectGuiSerialization::initialize(const ProjectGui* projectGui) { 
     std::list<boost::shared_ptr<NodeGui> > activeNodes = projectGui->getVisibleNodes();
     _serializedNodes.clear();
     for (std::list<boost::shared_ptr<NodeGui> >::iterator it = activeNodes.begin();it!=activeNodes.end();++it) {
         NodeGuiSerialization state;
         (*it)->serialize(&state);
         _serializedNodes.push_back(state);
         
         if ((*it)->getNode()->pluginID() == "Viewer") {
             ViewerInstance* viewer = dynamic_cast<ViewerInstance*>((*it)->getNode()->getLiveInstance());
             assert(viewer);
             ViewerTab* tab = projectGui->getGui()->getViewerTabForInstance(viewer);
             assert(tab);
             ViewerData viewerData;
             tab->getViewer()->getProjection(&viewerData.zoomLeft, &viewerData.zoomBottom, &viewerData.zoomFactor, &viewerData.zoomPAR);
             viewerData.userRoI = tab->getViewer()->getUserRegionOfInterest();
             viewerData.userRoIenabled = tab->getViewer()->isUserRegionOfInterestEnabled();
             viewerData.isClippedToProject = tab->isClippedToProject();
             viewerData.autoContrastEnabled = tab->isAutoContrastEnabled();
             viewerData.gain = tab->getGain();
             viewerData.colorSpace = tab->getColorSpace();
             viewerData.channels = tab->getChannelsString();
             viewerData.renderScaleActivated = tab->getRenderScaleActivated();
             viewerData.mipMapLevel = tab->getMipMapLevel();
             viewerData.zoomOrPanSinceLastFit = tab->getZoomOrPannedSinceLastFit();
             viewerData.wipeCompositingOp = (int)tab->getCompositingOperator();
             _viewersData.insert(std::make_pair(viewer->getNode()->getName_mt_safe(),viewerData));
         }
     }
     
    std::list<TabWidget*> tabWidgets = projectGui->getGui()->getPanes_mt_safe();
     for (std::list<TabWidget*>::const_iterator it = tabWidgets.begin(); it!= tabWidgets.end(); ++it) {
         QString widgetName = (*it)->objectName_mt_safe();
         if(widgetName.isEmpty()){
             qDebug() << "Warning: attempting to save the layout of an unnamed TabWidget, discarding.";
             continue;
         }
         
         PaneLayout layout;
         layout.parentingCreated = false;
         std::map<TabWidget*,bool> userSplits = (*it)->getUserSplits();
         for (std::map<TabWidget*,bool>::const_iterator split = userSplits.begin(); split!=userSplits.end(); ++split) {
             layout.splits.push_back(split->second);
         }
         layout.floating = (*it)->isFloating();
         if(layout.floating){
             QPoint pos = (*it)->pos_mt_safe();
             layout.posx = pos.x();
             layout.posy = pos.y();
         }else{
             //not releveant since the tab is not floating
             layout.posx = -1;
             layout.posy = -1;
         }
         
         QStringList tabNames = (*it)->getTabNames();
         for (int i = 0; i < tabNames.size(); ++i) {
             if(tabNames[i].isEmpty()){
                 qDebug() << "Warning: attempting to save the position of an unnamed tab, discarding.";
                 continue;
             }
             layout.tabs.push_back(tabNames[i].toStdString());
         }
         _layout.insert(std::make_pair(widgetName.toStdString(),layout));
     }
     
     ///now we do a second pass to insert for each layout what are its children splits
     for (std::map<std::string,PaneLayout>::iterator it = _layout.begin(); it!= _layout.end(); ++it) {
         if(!it->second.parentingCreated){
             createParenting(it);
         }
     }
     
     ///save application's splitters states
    std::list<Splitter*> splitters = projectGui->getGui()->getSplitters();
     for (std::list<Splitter*>::const_iterator it = splitters.begin(); it!= splitters.end(); ++it) {
         QByteArray ba = (*it)->saveState();
         ba = ba.toBase64();
         QString str(ba);
         _splittersStates.insert(std::make_pair((*it)->objectName_mt_safe().toStdString(),str.toStdString()));

     }
     
     _arePreviewTurnedOffGlobally = projectGui->getGui()->getNodeGraph()->areAllPreviewTurnedOff();
     
     
     ///save histograms
    std::list<Histogram*> histograms = projectGui->getGui()->getHistograms_mt_safe();
     for (std::list<Histogram*>::const_iterator it = histograms.begin(); it != histograms.end(); ++it) {
         _histograms.push_back((*it)->objectName().toStdString());
     }
    
    std::list<NodeBackDrop*> backdrops = projectGui->getGui()->getNodeGraph()->getActiveBackDrops();
    for (std::list<NodeBackDrop*>::iterator it = backdrops.begin(); it!=backdrops.end();++it) {
        NodeBackDropSerialization s;
        s.initialize(*it);
        _backdrops.push_back(s);
    }
     
}