<commit_before>//  Natron
//
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
 *Created by <NAME> on 6/1/2012.
 *contact: immarespond at gmail dot com
 *
 */

#include "ViewerInstance.h"

#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>

#include <QtConcurrentMap>

#include "Global/AppManager.h"

#include "Gui/Gui.h"
#include "Gui/ViewerTab.h"
#include "Gui/ViewerGL.h"
#include "Gui/TimeLineGui.h"

#include "Engine/Row.h"
#include "Engine/FrameEntry.h"
#include "Engine/MemoryFile.h"
#include "Engine/VideoEngine.h"
#include "Engine/OfxEffectInstance.h"
#include "Engine/ImageInfo.h"
#include "Engine/TimeLine.h"
#include "Engine/Cache.h"
#include "Engine/Log.h"
#include "Engine/Lut.h"

#include "Readers/Reader.h"



using namespace Natron;
using std::make_pair;
using boost::shared_ptr;


ViewerInstance::ViewerInstance(Node* node):
Natron::OutputEffectInstance(node)
, _uiContext(NULL)
, _pboIndex(0)
,_frameCount(1)
,_forceRenderMutex()
,_forceRender(false)
,_usingOpenGLCond()
,_usingOpenGLMutex()
,_usingOpenGL(false)
,_interThreadInfos()
,_buffer(NULL)
,_mustFreeBuffer(false)
,_renderArgsMutex()
,_exposure(1.)
,_colorSpace(Color::getLut(Color::LUT_DEFAULT_VIEWER))
,_lut(1)
{
    connectSlotsToViewerCache();
    connect(this,SIGNAL(doUpdateViewer()),this,SLOT(updateViewer()));
    
}

ViewerInstance::~ViewerInstance(){
    if(_uiContext && _uiContext->getGui())
        _uiContext->getGui()->removeViewerTab(_uiContext,true);
    if(_mustFreeBuffer)
        free(_buffer);
}

void ViewerInstance::connectSlotsToViewerCache(){
    Natron::CacheSignalEmitter* emitter = appPTR->getViewerCache().activateSignalEmitter();
    QObject::connect(emitter, SIGNAL(addedEntry()), this, SLOT(onCachedFrameAdded()));
    QObject::connect(emitter, SIGNAL(removedEntry()), this, SLOT(onCachedFrameAdded()));
    QObject::connect(emitter, SIGNAL(clearedInMemoryPortion()), this, SLOT(onViewerCacheCleared()));
}

void ViewerInstance::disconnectSlotsToViewerCache(){
    Natron::CacheSignalEmitter* emitter = appPTR->getViewerCache().activateSignalEmitter();
    QObject::disconnect(emitter, SIGNAL(addedEntry()), this, SLOT(onCachedFrameAdded()));
    QObject::disconnect(emitter, SIGNAL(removedEntry()), this, SLOT(onCachedFrameAdded()));
    QObject::disconnect(emitter, SIGNAL(clearedInMemoryPortion()), this, SLOT(onViewerCacheCleared()));
}
void ViewerInstance::initializeViewerTab(TabWidget* where){
    if(isLiveInstance()){
        _uiContext = getNode()->getApp()->addNewViewerTab(this,where);
    }
}

void ViewerInstance::cloneExtras(){
    _uiContext = dynamic_cast<ViewerInstance*>(getNode()->getLiveInstance())->getUiContext();
}

int ViewerInstance::activeInput() const{
    return dynamic_cast<InspectorNode*>(getNode())->activeInput();
}

Natron::Status ViewerInstance::getRegionOfDefinition(SequenceTime time,RectI* rod){
    EffectInstance* n = input(activeInput());
    if(n){
        return n->getRegionOfDefinition(time,rod);
    }else{
        return StatFailed;
    }
}

EffectInstance::RoIMap ViewerInstance::getRegionOfInterest(SequenceTime /*time*/,RenderScale /*scale*/,const RectI& renderWindow){
    RoIMap ret;
    EffectInstance* n = input(activeInput());
    if (n) {
        ret.insert(std::make_pair(n, renderWindow));
    }
    return ret;
}

void ViewerInstance::getFrameRange(SequenceTime *first,SequenceTime *last){
    SequenceTime inpFirst = 0,inpLast = 0;
    EffectInstance* n = input(activeInput());
    if(n){
        n->getFrameRange(&inpFirst,&inpLast);
    }
    *first = inpFirst;
    *last = inpLast;
}


Natron::Status ViewerInstance::renderViewer(SequenceTime time,bool fitToViewer){
    
#ifdef NATRON_LOG
    Natron::Log::beginFunction(getName(),"renderViewer");
    Natron::Log::print(QString("Time "+QString::number(time)).toStdString());
#endif
    
    ViewerGL *viewer = _uiContext->viewer;
    assert(viewer);
    double zoomFactor = viewer->getZoomFactor();
    
    RectI rod;
    Status stat = getRegionOfDefinition(time, &rod);
    if(stat == StatFailed){
#ifdef NATRON_LOG
        Natron::Log::print(QString("getRegionOfDefinition returned StatFailed.").toStdString());
        Natron::Log::endFunction(getName(),"renderViewer");
#endif
        return stat;
    }
    ifInfiniteclipRectToProjectDefault(&rod);
    if(fitToViewer){
        viewer->fitToFormat(rod);
        zoomFactor = viewer->getZoomFactor();
    }
    viewer->setRod(rod);
    Format dispW = getApp()->getProjectFormat();
    
    viewer->setDisplayingImage(true);
    
    if(!viewer->isClippingToDisplayWindow()){
        dispW.set(rod);
    }
    
    /*computing the RoI*/
    std::vector<int> rows;
    std::vector<int> columns;
    int bottom = std::max(rod.bottom(),dispW.bottom());
    int top = std::min(rod.top(),dispW.top());
    int left = std::max(rod.left(),dispW.left());
    int right = std::min(rod.right(), dispW.right());
    std::pair<int,int> rowSpan = viewer->computeRowSpan(bottom,top, &rows);
    std::pair<int,int> columnSpan = viewer->computeColumnSpan(left,right, &columns);
    
    TextureRect textureRect(columnSpan.first,rowSpan.first,columnSpan.second,rowSpan.second,columns.size(),rows.size());
#ifdef NATRON_LOG
    Natron::Log::print(QString("Image rect is..."
                               " xmin= "+QString::number(left)+
                               " ymin= "+QString::number(bottom)+
                               " xmax= "+QString::number(right)+
                               " ymax= "+QString::number(top)+
                               " Viewer RoI is...."+
                               " xmin= "+QString::number(textureRect.x)+
                               " ymin= "+QString::number(textureRect.y)+
                               " xmax= "+QString::number(textureRect.r+1)+
                               " ymax= "+QString::number(textureRect.t+1)).toStdString());
#endif
    if(textureRect.w == 0 || textureRect.h == 0){
#ifdef NATRON_LOG
        Natron::Log::print(QString("getRegionOfDefinition returned StatFailed.").toStdString());
        Natron::Log::endFunction(getName(),"renderViewer");
#endif
        return StatFailed;
    }
    _interThreadInfos._textureRect = textureRect;
    _interThreadInfos._bytesCount = _interThreadInfos._textureRect.w * _interThreadInfos._textureRect.h * 4;
    if(viewer->byteMode() == 0 && viewer->hasHardware()){<commit_msg>Don't return StatFailed in renderViewer when the texture rect is NULL<commit_after>//  Natron
//
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
 *Created by <NAME> on 6/1/2012.
 *contact: <EMAIL>
 *
 */

#include "ViewerInstance.h"

#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>

#include <QtConcurrentMap>

#include "Global/AppManager.h"

#include "Gui/Gui.h"
#include "Gui/ViewerTab.h"
#include "Gui/ViewerGL.h"
#include "Gui/TimeLineGui.h"

#include "Engine/Row.h"
#include "Engine/FrameEntry.h"
#include "Engine/MemoryFile.h"
#include "Engine/VideoEngine.h"
#include "Engine/OfxEffectInstance.h"
#include "Engine/ImageInfo.h"
#include "Engine/TimeLine.h"
#include "Engine/Cache.h"
#include "Engine/Log.h"
#include "Engine/Lut.h"

#include "Readers/Reader.h"



using namespace Natron;
using std::make_pair;
using boost::shared_ptr;


ViewerInstance::ViewerInstance(Node* node):
Natron::OutputEffectInstance(node)
, _uiContext(NULL)
, _pboIndex(0)
,_frameCount(1)
,_forceRenderMutex()
,_forceRender(false)
,_usingOpenGLCond()
,_usingOpenGLMutex()
,_usingOpenGL(false)
,_interThreadInfos()
,_buffer(NULL)
,_mustFreeBuffer(false)
,_renderArgsMutex()
,_exposure(1.)
,_colorSpace(Color::getLut(Color::LUT_DEFAULT_VIEWER))
,_lut(1)
{
    connectSlotsToViewerCache();
    connect(this,SIGNAL(doUpdateViewer()),this,SLOT(updateViewer()));
    
}

ViewerInstance::~ViewerInstance(){
    if(_uiContext && _uiContext->getGui())
        _uiContext->getGui()->removeViewerTab(_uiContext,true);
    if(_mustFreeBuffer)
        free(_buffer);
}

void ViewerInstance::connectSlotsToViewerCache(){
    Natron::CacheSignalEmitter* emitter = appPTR->getViewerCache().activateSignalEmitter();
    QObject::connect(emitter, SIGNAL(addedEntry()), this, SLOT(onCachedFrameAdded()));
    QObject::connect(emitter, SIGNAL(removedEntry()), this, SLOT(onCachedFrameAdded()));
    QObject::connect(emitter, SIGNAL(clearedInMemoryPortion()), this, SLOT(onViewerCacheCleared()));
}

void ViewerInstance::disconnectSlotsToViewerCache(){
    Natron::CacheSignalEmitter* emitter = appPTR->getViewerCache().activateSignalEmitter();
    QObject::disconnect(emitter, SIGNAL(addedEntry()), this, SLOT(onCachedFrameAdded()));
    QObject::disconnect(emitter, SIGNAL(removedEntry()), this, SLOT(onCachedFrameAdded()));
    QObject::disconnect(emitter, SIGNAL(clearedInMemoryPortion()), this, SLOT(onViewerCacheCleared()));
}
void ViewerInstance::initializeViewerTab(TabWidget* where){
    if(isLiveInstance()){
        _uiContext = getNode()->getApp()->addNewViewerTab(this,where);
    }
}

void ViewerInstance::cloneExtras(){
    _uiContext = dynamic_cast<ViewerInstance*>(getNode()->getLiveInstance())->getUiContext();
}

int ViewerInstance::activeInput() const{
    return dynamic_cast<InspectorNode*>(getNode())->activeInput();
}

Natron::Status ViewerInstance::getRegionOfDefinition(SequenceTime time,RectI* rod){
    EffectInstance* n = input(activeInput());
    if(n){
        return n->getRegionOfDefinition(time,rod);
    }else{
        return StatFailed;
    }
}

EffectInstance::RoIMap ViewerInstance::getRegionOfInterest(SequenceTime /*time*/,RenderScale /*scale*/,const RectI& renderWindow){
    RoIMap ret;
    EffectInstance* n = input(activeInput());
    if (n) {
        ret.insert(std::make_pair(n, renderWindow));
    }
    return ret;
}

void ViewerInstance::getFrameRange(SequenceTime *first,SequenceTime *last){
    SequenceTime inpFirst = 0,inpLast = 0;
    EffectInstance* n = input(activeInput());
    if(n){
        n->getFrameRange(&inpFirst,&inpLast);
    }
    *first = inpFirst;
    *last = inpLast;
}


Natron::Status ViewerInstance::renderViewer(SequenceTime time,bool fitToViewer){
    
#ifdef NATRON_LOG
    Natron::Log::beginFunction(getName(),"renderViewer");
    Natron::Log::print(QString("Time "+QString::number(time)).toStdString());
#endif
    
    ViewerGL *viewer = _uiContext->viewer;
    assert(viewer);
    double zoomFactor = viewer->getZoomFactor();
    
    RectI rod;
    Status stat = getRegionOfDefinition(time, &rod);
    if(stat == StatFailed){
#ifdef NATRON_LOG
        Natron::Log::print(QString("getRegionOfDefinition returned StatFailed.").toStdString());
        Natron::Log::endFunction(getName(),"renderViewer");
#endif
        return stat;
    }
    ifInfiniteclipRectToProjectDefault(&rod);
    if(fitToViewer){
        viewer->fitToFormat(rod);
        zoomFactor = viewer->getZoomFactor();
    }
    viewer->setRod(rod);
    Format dispW = getApp()->getProjectFormat();
    
    viewer->setDisplayingImage(true);
    
    if(!viewer->isClippingToDisplayWindow()){
        dispW.set(rod);
    }
    
    /*computing the RoI*/
    std::vector<int> rows;
    std::vector<int> columns;
    int bottom = std::max(rod.bottom(),dispW.bottom());
    int top = std::min(rod.top(),dispW.top());
    int left = std::max(rod.left(),dispW.left());
    int right = std::min(rod.right(), dispW.right());
    std::pair<int,int> rowSpan = viewer->computeRowSpan(bottom,top, &rows);
    std::pair<int,int> columnSpan = viewer->computeColumnSpan(left,right, &columns);
    
    TextureRect textureRect(columnSpan.first,rowSpan.first,columnSpan.second,rowSpan.second,columns.size(),rows.size());
#ifdef NATRON_LOG
    Natron::Log::print(QString("Image rect is..."
                               " xmin= "+QString::number(left)+
                               " ymin= "+QString::number(bottom)+
                               " xmax= "+QString::number(right)+
                               " ymax= "+QString::number(top)+
                               " Viewer RoI is...."+
                               " xmin= "+QString::number(textureRect.x)+
                               " ymin= "+QString::number(textureRect.y)+
                               " xmax= "+QString::number(textureRect.r+1)+
                               " ymax= "+QString::number(textureRect.t+1)).toStdString());
#endif
    if(textureRect.w == 0 || textureRect.h == 0){
        return StatOK;
    }
    _interThreadInfos._textureRect = textureRect;
    _interThreadInfos._bytesCount = _interThreadInfos._textureRect.w * _interThreadInfos._textureRect.h * 4;
    if(viewer->byteMode() == 0 && viewer->hasHardware()){
{'fraction_non_alphanumeric': 0.15230709577355564, 'fraction_numerical': 0.0034121752617293525, 'mean_word_length': 4.093206951026856, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 72, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4194317', 'n_tokens_mistral': 4181, 'n_tokens_neox': 4093, 'n_words': 676}