void KnobGui::setInterpolationForDimensions(QAction* action, KeyframeTypeEnum interp) { if (!action) { return; } int dimension = action->data().toInt(); KnobPtr knob = getKnob(); for (int i = 0; i < knob->getDimension(); ++i) { if ( (dimension == -1) || (dimension == i) ) { boost::shared_ptr<Curve> c = knob->getCurve(ViewIdx(0), i); if (c) { int kfCount = c->getKeyFramesCount(); for (int j = 0; j < kfCount; ++j) { c->setKeyFrameInterpolation(interp, j); } boost::shared_ptr<Curve> guiCurve = getCurve(ViewIdx(0), i); if (guiCurve) { guiCurve->clone(*c); } } } } if ( knob->getHolder() ) { knob->getHolder()->incrHashAndEvaluate(knob->getEvaluateOnChange(), false); } Q_EMIT keyInterpolationChanged(); }
void KnobGui::setAllKeyframeMarkersOnTimeline(int dimension) { KnobPtr knob = getKnob(); AppInstPtr app = knob->getHolder()->getApp(); assert(app); std::list<SequenceTime> times; if (dimension == -1) { int dim = knob->getDimension(); for (int i = 0; i < dim; ++i) { KeyFrameSet kfs = knob->getCurve(ViewIdx(0), i)->getKeyFrames_mt_safe(); for (KeyFrameSet::iterator it = kfs.begin(); it != kfs.end(); ++it) { times.push_back( it->getTime() ); } } } else { KeyFrameSet kfs = knob->getCurve(ViewIdx(0), dimension)->getKeyFrames_mt_safe(); for (KeyFrameSet::iterator it = kfs.begin(); it != kfs.end(); ++it) { times.push_back( it->getTime() ); } } app->addMultipleKeyframeIndicatorsAdded(times, true); }
void BezierCurve::getFeatherPointPosition(int index, double time, double* x, double *y, double *lx, double *ly, double *rx, double *ry) const { boost::shared_ptr<BezierCP> cp = _bezier->getFeatherPointAtIndex(index); cp->getPositionAtTime(true, time, ViewIdx(0), x, y); cp->getLeftBezierPointAtTime(true, time, ViewIdx(0), lx, ly); cp->getRightBezierPointAtTime(true, time, ViewIdx(0), rx, ry); }
void ViewerNodePrivate::refreshInputChoices(bool resetChoiceIfNotFound) { // Refresh the A and B input choices KnobChoicePtr aInputKnob = aInputNodeChoiceKnob.lock(); KnobChoicePtr bInputKnob = bInputNodeChoiceKnob.lock(); ViewerCompositingOperatorEnum operation = (ViewerCompositingOperatorEnum)blendingModeChoiceKnob.lock()->getValue(); bInputKnob->setEnabled(operation != eViewerCompositingOperatorNone); std::vector<ChoiceOption> entries; entries.push_back(ChoiceOption("-", "", "")); int nInputs = _publicInterface->getMaxInputCount(); for (int i = 0; i < nInputs; ++i) { NodePtr inputNode = _publicInterface->getNode()->getRealInput(i); if (!inputNode) { continue; } std::string optionID; { std::stringstream ss; ss << i; optionID = ss.str(); } entries.push_back(ChoiceOption(optionID, inputNode->getLabel(), "")); } ChoiceOption currentAChoice = aInputKnob->getActiveEntry(); ChoiceOption currentBChoice = bInputKnob->getActiveEntry(); aInputKnob->populateChoices(entries); bInputKnob->populateChoices(entries); if (resetChoiceIfNotFound) { if (currentAChoice.id == "-" || !aInputKnob->isActiveEntryPresentInEntries(ViewIdx(0))) { aInputKnob->setValue(entries.size() > 1 ? 1 : 0); } if (currentBChoice.id == "-" || !bInputKnob->isActiveEntryPresentInEntries(ViewIdx(0))) { bInputKnob->setValue(entries.size() > 1 ? 1 : 0); } } if (uiContext) { if ( (operation == eViewerCompositingOperatorNone) || !bInputKnob->isEnabled() || bInputKnob->getActiveEntry().id.empty() ) { uiContext->setInfoBarVisible(1, false); } else if (operation != eViewerCompositingOperatorNone) { uiContext->setInfoBarVisible(1, true); } } } // refreshInputChoices
void AnimationModuleSelectionModel::addAnimatedItemsWithoutKeyframes(const AnimItemBasePtr& item, DimSpec dim, ViewSetSpec viewSpec, AnimItemDimViewKeyFramesMap* result) { if (!result) { return; } std::list<ViewIdx> views = item->getViewsList(); int nDims = item->getNDimensions(); if (viewSpec.isAll()) { for (std::list<ViewIdx>::const_iterator it3 = views.begin(); it3 != views.end(); ++it3) { if (dim.isAll()) { for (int i = 0; i < nDims; ++i) { QTreeWidgetItem* treeItem = item->getTreeItem(DimIdx(i), *it3); if (AnimationModuleTreeView::isItemVisibleRecursive(treeItem)) { AnimItemDimViewIndexID key(item, *it3, DimIdx(i)); KeyFrameWithStringSet &keysForItem = (*result)[key]; (void)keysForItem; } } } else { QTreeWidgetItem* treeItem = item->getTreeItem(DimIdx(dim), *it3); if (AnimationModuleTreeView::isItemVisibleRecursive(treeItem)) { AnimItemDimViewIndexID key(item, *it3, DimIdx(dim)); KeyFrameWithStringSet &keysForItem = (*result)[key]; (void)keysForItem; } } } } else { if (dim.isAll()) { for (int i = 0; i < nDims; ++i) { QTreeWidgetItem* treeItem = item->getTreeItem(DimIdx(i), ViewIdx(viewSpec)); if (AnimationModuleTreeView::isItemVisibleRecursive(treeItem)) { AnimItemDimViewIndexID key(item, ViewIdx(viewSpec), DimIdx(i)); KeyFrameWithStringSet &keysForItem = (*result)[key]; (void)keysForItem; } } } else { QTreeWidgetItem* treeItem = item->getTreeItem(DimIdx(dim), ViewIdx(viewSpec)); if (AnimationModuleTreeView::isItemVisibleRecursive(treeItem)) { AnimItemDimViewIndexID key(item, ViewIdx(viewSpec), DimIdx(dim)); KeyFrameWithStringSet &keysForItem = (*result)[key]; (void)keysForItem; } } } } // addAnimatedItemsWithoutKeyframes
void DSPasteKeysCommand::setKeyValueFromKnob(const KnobIPtr& knob, double keyTime, KeyFrame* key) { KnobDoubleBasePtr isDouble = toKnobDoubleBase(knob); KnobBoolBasePtr isBool = toKnobBoolBase(knob); KnobIntBasePtr isInt = toKnobIntBase(knob); KnobStringBasePtr isString = toKnobStringBase(knob); if (isDouble) { key->setValue( isDouble->getValueAtTime(keyTime) ); } else if (isBool) { key->setValue( isBool->getValueAtTime(keyTime) ); } else if (isInt) { key->setValue( isInt->getValueAtTime(keyTime) ); } else if (isString) { std::string v = isString->getValueAtTime(keyTime); double keyFrameValue = 0.; AnimatingKnobStringHelperPtr isStringAnimatedKnob = boost::dynamic_pointer_cast<AnimatingKnobStringHelper>(isString); assert(isStringAnimatedKnob); if (isStringAnimatedKnob) { isStringAnimatedKnob->stringToKeyFrameValue(keyTime, ViewIdx(0), v, &keyFrameValue); } key->setValue(keyFrameValue); } }
void KnobGui::onRemoveKeyActionTriggered() { QAction* action = qobject_cast<QAction*>( sender() ); assert(action); int dim = action->data().toInt(); KnobPtr knob = getKnob(); assert( knob->getHolder()->getApp() ); //get the current time on the global timeline SequenceTime time = knob->getHolder()->getApp()->getTimeLine()->currentFrame(); std::map<boost::shared_ptr<CurveGui>, std::vector<KeyFrame > > toRemove; KnobGuiPtr thisShared = shared_from_this(); for (int i = 0; i < knob->getDimension(); ++i) { if ( (dim == -1) || (i == dim) ) { std::list<boost::shared_ptr<CurveGui> > curves = getGui()->getCurveEditor()->findCurve(thisShared, i); for (std::list<boost::shared_ptr<CurveGui> >::iterator it = curves.begin(); it != curves.end(); ++it) { KeyFrame kf; bool foundKey = knob->getCurve(ViewIdx(0), i)->getKeyFrameWithTime(time, &kf); if (foundKey) { std::vector<KeyFrame > vect; vect.push_back(kf); toRemove.insert( std::make_pair(*it, vect) ); } } } } pushUndoCommand( new RemoveKeysCommand(getGui()->getCurveEditor()->getCurveWidget(), toRemove) ); }
std::pair<ImagePtr, RectD> TrackMarker::getMarkerImage(TimeValue time, const RectD& roi) const { assert( !roi.isNull() ); NodePtr node = getModel()->getNode(); NodePtr input = node->getInput(0); if (!input) { return std::make_pair(ImagePtr(), roi); } TreeRender::CtorArgsPtr args(new TreeRender::CtorArgs); { args->treeRootEffect = input->getEffectInstance(); args->time = time; args->view = ViewIdx(0); // Render default plane args->plane = 0; args->mipMapLevel = 0; args->proxyScale = RenderScale(1.); args->canonicalRoI = &roi; args->draftMode = false; args->playback = false; args->byPassCache = false; } TreeRenderPtr render = TreeRender::create(args); FrameViewRequestPtr outputRequest; ActionRetCodeEnum stat = render->launchRender(&outputRequest); if (isFailureRetCode(stat)) { return std::make_pair(ImagePtr(), roi); } ImagePtr sourceImage = outputRequest->getRequestedScaleImagePlane(); // Make sure the Natron image rendered is RGBA full rect and on CPU, we don't support other formats if (sourceImage->getStorageMode() != eStorageModeRAM) { Image::InitStorageArgs initArgs; initArgs.bounds = sourceImage->getBounds(); initArgs.plane = sourceImage->getLayer(); initArgs.bufferFormat = eImageBufferLayoutRGBAPackedFullRect; initArgs.storage = eStorageModeRAM; initArgs.bitdepth = sourceImage->getBitDepth(); ImagePtr tmpImage = Image::create(initArgs); if (!tmpImage) { return std::make_pair(ImagePtr(), roi); } Image::CopyPixelsArgs cpyArgs; cpyArgs.roi = initArgs.bounds; tmpImage->copyPixels(*sourceImage, cpyArgs); sourceImage = tmpImage; } return std::make_pair(sourceImage, roi); } // TrackMarker::getMarkerImage
std::string KnobFile::getFileName(int time, ViewSpec view) { if (!_isInputImage) { return getValue(0, view); } else { ///try to interpret the pattern and generate a filename if indexes are found std::vector<std::string> views; if ( getHolder() && getHolder()->getApp() ) { views = getHolder()->getApp()->getProject()->getProjectViewNames(); } if ( !view.isViewIdx() ) { view = ViewIdx(0); } return SequenceParsing::generateFileNameFromPattern(getValue( 0, ViewIdx(0) ), views, time, view); } }
void ViewerNode::setRefreshButtonDown(bool down) { KnobButtonPtr knob = _imp->refreshButtonKnob.lock(); // Ignore evaluation ScopedChanges_RAII changes(this, true); knob->setValue(down, ViewIdx(0), DimIdx(0), eValueChangedReasonTimeChanged); }
void TrackMarker::getCenterKeyframes(std::set<double>* keyframes) const { CurvePtr curve = _imp->center.lock()->getAnimationCurve(ViewIdx(0), DimIdx(0)); assert(curve); KeyFrameSet keys = curve->getKeyFrames_mt_safe(); for (KeyFrameSet::iterator it = keys.begin(); it != keys.end(); ++it) { keyframes->insert( it->getTime() ); } }
void KnobFile::reloadFile() { assert( getHolder() ); EffectInstance* effect = dynamic_cast<EffectInstance*>( getHolder() ); if (effect) { effect->purgeCaches(); effect->clearPersistentMessage(false); } evaluateValueChange(0, getCurrentTime(), ViewIdx(0), eValueChangedReasonNatronInternalEdited); }
SetExpressionCommand::SetExpressionCommand(const KnobIPtr & knob, bool hasRetVar, DimSpec dimension, ViewSetSpec view, const std::string& expr, QUndoCommand *parent) : QUndoCommand(parent) , _knob(knob) , _oldExprs() , _newExpr(expr) , _hasRetVar(hasRetVar) , _dimension(dimension) , _view(view) { int nDims = knob->getNDimensions(); std::list<ViewIdx> allViews = knob->getViewsList(); if (dimension.isAll()) { for (int i = 0; i < nDims; ++i) { if (view.isAll()) { for (std::list<ViewIdx>::const_iterator it = allViews.begin(); it!=allViews.end(); ++it) { getOldExprForDimView(knob, DimIdx(i), *it, &_oldExprs); } } else { getOldExprForDimView(knob, DimIdx(i), ViewIdx(view), &_oldExprs); } } } else { if (view.isAll()) { for (std::list<ViewIdx>::const_iterator it = allViews.begin(); it!=allViews.end(); ++it) { getOldExprForDimView(knob, DimIdx(dimension), *it, &_oldExprs); } } else { getOldExprForDimView(knob, DimIdx(dimension), ViewIdx(view), &_oldExprs); } } setText( tr("Set Expression") ); }
void DSTransformKeysCommand::redo() { /* The view is going to get MANY update() calls since every knob change will trigger a computeNodeRange() in DopeSheetView We explicitly disable update on the dopesheet view and re-enable it afterwards. */ DopeSheetView* view = _model->getDopesheetView(); view->setUpdatesEnabled(false); std::list<KnobHolderPtr> differentKnobs; for (TransformKeys::iterator it = _keys.begin(); it != _keys.end(); ++it) { KnobHolderPtr holder = it->first->getInternalKnob()->getHolder(); if (holder) { if ( std::find(differentKnobs.begin(), differentKnobs.end(), holder) == differentKnobs.end() ) { differentKnobs.push_back(holder); holder->beginChanges(); } } } if (!_firstRedoCalled) { for (TransformKeys::iterator it = _keys.begin(); it != _keys.end(); ++it) { it->second.oldCurve.reset( new Curve( *it->first->getInternalKnob()->getCurve( ViewIdx(0), it->first->getDimension() ) ) ); } for (TransformKeys::iterator it = _keys.begin(); it != _keys.end(); ++it) { for (DSKeyPtrList::iterator it2 = it->second.keys.begin(); it2 != it->second.keys.end(); ++it2) { transformKey(*it2); } } for (TransformKeys::iterator it = _keys.begin(); it != _keys.end(); ++it) { it->second.newCurve.reset( new Curve( *it->first->getInternalKnob()->getCurve( ViewIdx(0), it->first->getDimension() ) ) ); } _firstRedoCalled = true; } else { for (TransformKeys::iterator it = _keys.begin(); it != _keys.end(); ++it) { it->first->getInternalKnob()->cloneCurve(ViewIdx(0), it->first->getDimension(), *it->second.newCurve); } } for (std::list<KnobHolderPtr>::iterator it = differentKnobs.begin(); it != differentKnobs.end(); ++it) { (*it)->endChanges(); } view->setUpdatesEnabled(true); _model->refreshSelectionBboxAndRedrawView(); }
void KnobGui::removeAllKeyframeMarkersOnTimeline(int dimension) { KnobPtr knob = getKnob(); if ( knob->getHolder() && knob->getHolder()->getApp() && !knob->getIsSecret() && ( knob->isDeclaredByPlugin() || knob->isUserKnob() ) ) { AppInstPtr app = knob->getHolder()->getApp(); assert(app); std::list<SequenceTime> times; std::set<SequenceTime> tmpTimes; if (dimension == -1) { int dim = knob->getDimension(); for (int i = 0; i < dim; ++i) { boost::shared_ptr<Curve> curve = knob->getCurve(ViewIdx(0), i); if (curve) { KeyFrameSet kfs = curve->getKeyFrames_mt_safe(); for (KeyFrameSet::iterator it = kfs.begin(); it != kfs.end(); ++it) { tmpTimes.insert( it->getTime() ); } } } for (std::set<SequenceTime>::iterator it = tmpTimes.begin(); it != tmpTimes.end(); ++it) { times.push_back(*it); } } else { boost::shared_ptr<Curve> curve = knob->getCurve(ViewIdx(0), dimension); if (curve) { KeyFrameSet kfs = curve->getKeyFrames_mt_safe(); for (KeyFrameSet::iterator it = kfs.begin(); it != kfs.end(); ++it) { times.push_back( it->getTime() ); } } } if ( !times.empty() ) { app->removeMultipleKeyframeIndicator(times, true); } } }
void SetExpressionCommand::undo() { KnobIPtr knob = _knob.lock(); if (!knob) { return; } knob->beginChanges(); try { int nDims = knob->getNDimensions(); std::list<ViewIdx> allViews = knob->getViewsList(); if (_dimension.isAll()) { for (int i = 0; i < nDims; ++i) { if (_view.isAll()) { for (std::list<ViewIdx>::const_iterator it = allViews.begin(); it!=allViews.end(); ++it) { setOldExprForDimView(knob, DimIdx(i), *it, _oldExprs); } } else { setOldExprForDimView(knob, DimIdx(i), ViewIdx(_view), _oldExprs); } } } else { if (_view.isAll()) { for (std::list<ViewIdx>::const_iterator it = allViews.begin(); it!=allViews.end(); ++it) { setOldExprForDimView(knob, DimIdx(_dimension), *it, _oldExprs); } } else { setOldExprForDimView(knob, DimIdx(_dimension), ViewIdx(_view), _oldExprs); } } } catch (...) { Dialogs::errorDialog( tr("Expression").toStdString(), tr("The expression is invalid.").toStdString() ); } knob->endChanges(); }
static void deleteKnobAnimation(const std::set<double>& userKeyframes, const KnobIPtr& knob, DeleteKnobAnimationEnum type, double currentTime) { for (int i = 0; i < knob->getNDimensions(); ++i) { CurvePtr curve = knob->getAnimationCurve(ViewIdx(0), DimIdx(i)); assert(curve); KeyFrameSet keys = curve->getKeyFrames_mt_safe(); std::list<double> toRemove; switch (type) { case eDeleteKnobAnimationAll: { for (KeyFrameSet::iterator it = keys.begin(); it != keys.end(); ++it) { std::set<double>::iterator found = userKeyframes.find( it->getTime() ); if ( found == userKeyframes.end() ) { toRemove.push_back( it->getTime() ); } } break; } case eDeleteKnobAnimationBeforeTime: { for (KeyFrameSet::iterator it = keys.begin(); it != keys.end(); ++it) { if (it->getTime() >= currentTime) { break; } std::set<double>::iterator found = userKeyframes.find( it->getTime() ); if ( found == userKeyframes.end() ) { toRemove.push_back( it->getTime() ); } } break; } case eDeleteKnobAnimationAfterTime: { for (KeyFrameSet::reverse_iterator it = keys.rbegin(); it != keys.rend(); ++it) { if (it->getTime() <= currentTime) { break; } std::set<double>::iterator found = userKeyframes.find( it->getTime() ); if ( found == userKeyframes.end() ) { toRemove.push_back( it->getTime() ); } } break; } } knob->deleteValuesAtTime(toRemove, ViewSetSpec::all(), DimIdx(i), eValueChangedReasonUserEdited); } }
void KnobGui::onSetKeyActionTriggered() { QAction* action = qobject_cast<QAction*>( sender() ); assert(action); int dim = action->data().toInt(); KnobPtr knob = getKnob(); assert( knob->getHolder()->getApp() ); //get the current time on the global timeline SequenceTime time = knob->getHolder()->getApp()->getTimeLine()->currentFrame(); AddKeysCommand::KeysToAddList toAdd; KnobGuiPtr thisShared = shared_from_this(); for (int i = 0; i < knob->getDimension(); ++i) { if ( (dim == -1) || (i == dim) ) { std::list<boost::shared_ptr<CurveGui> > curves = getGui()->getCurveEditor()->findCurve(thisShared, i); for (std::list<boost::shared_ptr<CurveGui> >::iterator it = curves.begin(); it != curves.end(); ++it) { AddKeysCommand::KeyToAdd keyToAdd; KeyFrame kf; kf.setTime(time); Knob<int>* isInt = dynamic_cast<Knob<int>*>( knob.get() ); Knob<bool>* isBool = dynamic_cast<Knob<bool>*>( knob.get() ); AnimatingKnobStringHelper* isString = dynamic_cast<AnimatingKnobStringHelper*>( knob.get() ); Knob<double>* isDouble = dynamic_cast<Knob<double>*>( knob.get() ); if (isInt) { kf.setValue( isInt->getValue(i) ); } else if (isBool) { kf.setValue( isBool->getValue(i) ); } else if (isDouble) { kf.setValue( isDouble->getValue(i) ); } else if (isString) { std::string v = isString->getValue(i); double dv; isString->stringToKeyFrameValue(time, ViewIdx(0), v, &dv); kf.setValue(dv); } keyToAdd.keyframes.push_back(kf); keyToAdd.curveUI = *it; keyToAdd.knobUI = thisShared; keyToAdd.dimension = i; toAdd.push_back(keyToAdd); } } } pushUndoCommand( new AddKeysCommand(getGui()->getCurveEditor()->getCurveWidget(), toAdd) ); }
QString KnobOutputFile::generateFileNameAtTime(SequenceTime time, ViewSpec view) { std::vector<std::string> views; if ( getHolder() && getHolder()->getApp() ) { views = getHolder()->getApp()->getProject()->getProjectViewNames(); } if ( !view.isViewIdx() ) { view = ViewIdx(0); } return QString::fromUtf8( SequenceParsing::generateFileNameFromPattern(getValue( 0, ViewIdx(0) ), views, time, view).c_str() ); }
FramesNeededMap OneViewNode::getFramesNeeded(double time, ViewIdx /*view*/) { FramesNeededMap ret; FrameRangesMap& rangeMap = ret[0]; KnobChoicePtr viewKnob = _imp->viewKnob.lock(); int view_i = viewKnob->getValue(); std::vector<RangeD>& ranges = rangeMap[ViewIdx(view_i)]; ranges.resize(1); ranges[0].min = ranges[0].max = time; return ret; }
void RestoreDefaultsCommand::undo() { assert( _clones.size() == _knobs.size() ); std::list<SequenceTime> times; KnobPtr first = _knobs.front().lock(); AppInstance* app = first->getHolder()->getApp(); assert(app); std::list<KnobWPtr >::const_iterator itClone = _clones.begin(); for (std::list<KnobWPtr >::const_iterator it = _knobs.begin(); it != _knobs.end(); ++it, ++itClone) { KnobPtr itKnob = it->lock(); if (!itKnob) { continue; } KnobPtr itCloneKnob = itClone->lock(); if (!itCloneKnob) { continue; } itKnob->cloneAndUpdateGui( itCloneKnob.get() ); if ( itKnob->getHolder()->getApp() ) { int dim = itKnob->getDimension(); for (int i = 0; i < dim; ++i) { if ( (i == _targetDim) || (_targetDim == -1) ) { boost::shared_ptr<Curve> c = itKnob->getCurve(ViewIdx(0), i); if (c) { KeyFrameSet kfs = c->getKeyFrames_mt_safe(); for (KeyFrameSet::iterator it = kfs.begin(); it != kfs.end(); ++it) { times.push_back( std::floor(it->getTime() + 0.5) ); } } } } } } app->addMultipleKeyframeIndicatorsAdded(times, true); first->getHolder()->incrHashAndEvaluate(true, true); if ( first->getHolder()->getApp() ) { first->getHolder()->getApp()->redrawAllViewers(); } setText( tr("Restore default value(s)") ); }
void KnobGui::onShowInCurveEditorActionTriggered() { KnobPtr knob = getKnob(); assert( knob->getHolder()->getApp() ); getGui()->setCurveEditorOnTop(); std::vector<boost::shared_ptr<Curve> > curves; for (int i = 0; i < knob->getDimension(); ++i) { boost::shared_ptr<Curve> c = getCurve(ViewIdx(0), i); if ( c->isAnimated() ) { curves.push_back(c); } } if ( !curves.empty() ) { getGui()->getCurveEditor()->centerOn(curves); } }
bool OneViewNode::isIdentity(double time, const RenderScale & /*scale*/, const RectI & /*roi*/, ViewIdx /*view*/, double* inputTime, ViewIdx* inputView, int* inputNb) { KnobChoicePtr viewKnob = _imp->viewKnob.lock(); int view_i = viewKnob->getValue(); *inputView = ViewIdx(view_i); *inputNb = 0; *inputTime = time; return true; }
bool areToPointsAnimated() const { bool hasAnimation = true; for (int i = 0; i < 4; ++i) { KnobDoublePtr knob = to[i].lock(); for (int d = 0; d < 2; ++d) { bool dimHasAnim = knob->isAnimated(DimIdx(d), ViewIdx(0)); if (!dimHasAnim) { hasAnimation = false; break; } } if (!hasAnimation) { break; } } return hasAnimation; }
void TrackMarker::clearAnimationAfterTime(TimeValue time) { std::set<double> userKeyframes; getMasterKeyFrameTimes(ViewIdx(0), &userKeyframes); KnobIPtr offsetKnob = getOffsetKnob(); assert(offsetKnob); deleteKnobAnimation(userKeyframes, offsetKnob, eDeleteKnobAnimationAfterTime, time); KnobIPtr centerKnob = getCenterKnob(); assert(centerKnob); deleteKnobAnimation(userKeyframes, centerKnob, eDeleteKnobAnimationAfterTime, time); KnobIPtr errorKnob = getErrorKnob(); assert(errorKnob); deleteKnobAnimation(userKeyframes, errorKnob, eDeleteKnobAnimationAfterTime, time); }
int TrackMarker::getReferenceFrame(TimeValue time, int frameStep) const { QMutexLocker k(&_imp->trackMutex); std::set<double> userKeyframes; getMasterKeyFrameTimes(ViewIdx(0), &userKeyframes); std::set<double>::iterator upper = userKeyframes.upper_bound(time); if ( upper == userKeyframes.end() ) { //all keys are lower than time, pick the last one if ( !userKeyframes.empty() ) { return *userKeyframes.rbegin(); } // no keyframe - use the previous/next as reference return time - frameStep; } else { if ( upper == userKeyframes.begin() ) { ///all keys are greater than time return *upper; } int upperKeyFrame = *upper; ///If we find "time" as a keyframe, then use it --upper; int lowerKeyFrame = *upper; if (lowerKeyFrame == time) { return time; } /// return the nearest from time return (time - lowerKeyFrame) < (upperKeyFrame - time) ? lowerKeyFrame : upperKeyFrame; } }
void TrackerHelper::trackMarkers(const std::list<TrackMarkerPtr >& markers, TimeValue start, TimeValue end, TimeValue frameStep, const ViewerNodePtr& viewer) { if ( markers.empty() ) { Q_EMIT trackingFinished(); return; } TrackerParamsProviderPtr provider = _imp->provider.lock(); if (!provider) { Q_EMIT trackingFinished(); return; } NodePtr trackerNode = provider->getTrackerNode(); if (!trackerNode) { Q_EMIT trackingFinished(); return; } if (trackerNode->hasMandatoryInputDisconnected()) { Q_EMIT trackingFinished(); return; } // The channels we are going to use for tracking bool enabledChannels[3]; provider->getTrackChannels(&enabledChannels[0], &enabledChannels[1], &enabledChannels[2]); double formatWidth, formatHeight; Format f; trackerNode->getApp()->getProject()->getProjectDefaultFormat(&f); formatWidth = f.width(); formatHeight = f.height(); bool autoKeyingOnEnabledParamEnabled = provider->canDisableMarkersAutomatically(); /// The accessor and its cache is local to a track operation, it is wiped once the whole sequence track is finished. boost::shared_ptr<TrackerFrameAccessor> accessor( new TrackerFrameAccessor(trackerNode, enabledChannels, formatHeight) ); boost::shared_ptr<mv::AutoTrack> trackContext( new mv::AutoTrack( accessor.get() ) ); std::vector<TrackMarkerAndOptionsPtr > trackAndOptions; mv::TrackRegionOptions mvOptions; /* Get the global parameters for the LivMV track: pre-blur sigma, No iterations, normalized intensities, etc... */ _imp->beginLibMVOptionsForTrack(&mvOptions); /* For the given markers, do the following: - Get the "User" keyframes that have been set and create a LibMV marker for each keyframe as well as for the "start" time - Set the "per-track" parameters that were given by the user, that is the mv::TrackRegionOptions - t->mvMarker will contain the marker that evolves throughout the tracking */ int trackIndex = 0; for (std::list<TrackMarkerPtr >::const_iterator it = markers.begin(); it != markers.end(); ++it, ++trackIndex) { if (autoKeyingOnEnabledParamEnabled) { (*it)->setEnabledAtTime(start, true); } TrackMarkerAndOptionsPtr t(new TrackMarkerAndOptions); t->natronMarker = *it; int mode_i = (*it)->getMotionModelKnob()->getValue(); mvOptions.mode = motionModelIndexToLivMVMode(mode_i); // Set a keyframe on the marker to initialize its position { KnobDoublePtr centerKnob = (*it)->getCenterKnob(); std::vector<double> values(2); values[0] = centerKnob->getValueAtTime(start, DimIdx(0)); values[1] = centerKnob->getValueAtTime(start, DimIdx(1)); centerKnob->setValueAtTimeAcrossDimensions(start, values); } // For a translation warp, we do not need to add an animation curve for the pattern which stays constant. if (mvOptions.mode != libmv::TrackRegionOptions::TRANSLATION) { KnobDoublePtr patternCorners[4]; patternCorners[0] = (*it)->getPatternBtmLeftKnob(); patternCorners[1] = (*it)->getPatternBtmRightKnob(); patternCorners[2] = (*it)->getPatternTopRightKnob(); patternCorners[3] = (*it)->getPatternTopLeftKnob(); for (int c = 0; c < 4; ++c) { KnobDoublePtr k = patternCorners[c]; std::vector<double> values(2); values[0] = k->getValueAtTime(start, DimIdx(0)); values[1] = k->getValueAtTime(start, DimIdx(1)); k->setValueAcrossDimensions(values); } } std::set<double> userKeys; t->natronMarker->getMasterKeyFrameTimes(ViewIdx(0), &userKeys); if ( userKeys.empty() ) { // Set a user keyframe on tracking start if the marker does not have any user keys t->natronMarker->setKeyFrame(start, ViewSetSpec(0), 0); } PreviouslyTrackedFrameSet previousFramesOrdered; // Make sure to create a marker at the start time userKeys.insert(start); // Add a libmv marker for all keyframes for (std::set<double>::iterator it2 = userKeys.begin(); it2 != userKeys.end(); ++it2) { // Add the marker to the markers ordered only if it can contribute to predicting its next position if ( ( (frameStep > 0) && (*it2 <= start) ) || ( (frameStep < 0) && (*it2 >= start) ) ) { previousFramesOrdered.insert( PreviouslyComputedTrackFrame(TimeValue(*it2), true) ); } } //For all already tracked frames which are not keyframes, add them to the AutoTrack too std::set<double> centerKeys; t->natronMarker->getCenterKeyframes(¢erKeys); for (std::set<double>::iterator it2 = centerKeys.begin(); it2 != centerKeys.end(); ++it2) { if ( userKeys.find(*it2) != userKeys.end() ) { continue; } // Add the marker to the markers ordered only if it can contribute to predicting its next position if ( ( ( (frameStep > 0) && (*it2 < start) ) || ( (frameStep < 0) && (*it2 > start) ) ) ) { previousFramesOrdered.insert( PreviouslyComputedTrackFrame(TimeValue(*it2), false) ); } } // Taken from libmv, only initialize the filter to this amount of frames (max) const int max_frames_to_predict_from = 20; std::list<mv::Marker> previouslyComputedMarkersOrdered; // Find the first keyframe that's not considered to go before start or end PreviouslyTrackedFrameSet::iterator prevFramesIt = previousFramesOrdered.lower_bound(PreviouslyComputedTrackFrame(start, false)); if (frameStep < 0) { if (prevFramesIt != previousFramesOrdered.end()) { while (prevFramesIt != previousFramesOrdered.end() && (int)previouslyComputedMarkersOrdered.size() != max_frames_to_predict_from) { mv::Marker mvMarker; TrackerHelperPrivate::natronTrackerToLibMVTracker(true, enabledChannels, *t->natronMarker, trackIndex, TimeValue(prevFramesIt->frame), frameStep, formatHeight, &mvMarker); trackContext->AddMarker(mvMarker); // insert in the front of the list so that the order is reversed previouslyComputedMarkersOrdered.push_front(mvMarker); ++prevFramesIt; } } // previouslyComputedMarkersOrdered is now ordererd by decreasing order } else { if (prevFramesIt != previousFramesOrdered.end()) { while (prevFramesIt != previousFramesOrdered.begin() && (int)previouslyComputedMarkersOrdered.size() != max_frames_to_predict_from) { mv::Marker mvMarker; TrackerHelperPrivate::natronTrackerToLibMVTracker(true, enabledChannels, *t->natronMarker, trackIndex, TimeValue(prevFramesIt->frame), frameStep, formatHeight, &mvMarker); trackContext->AddMarker(mvMarker); // insert in the front of the list so that the order is reversed previouslyComputedMarkersOrdered.push_front(mvMarker); --prevFramesIt; } if (prevFramesIt == previousFramesOrdered.begin() && (int)previouslyComputedMarkersOrdered.size() != max_frames_to_predict_from) { mv::Marker mvMarker; TrackerHelperPrivate::natronTrackerToLibMVTracker(true, enabledChannels, *t->natronMarker, trackIndex, TimeValue(prevFramesIt->frame), frameStep, formatHeight, &mvMarker); trackContext->AddMarker(mvMarker); // insert in the front of the list so that the order is reversed previouslyComputedMarkersOrdered.push_front(mvMarker); } } // previouslyComputedMarkersOrdered is now ordererd by increasing order } // There must be at least 1 marker at the start time assert( !previouslyComputedMarkersOrdered.empty() ); // Initialise the kalman state with the marker at the position std::list<mv::Marker>::iterator mIt = previouslyComputedMarkersOrdered.begin(); t->mvState.Init(*mIt, frameStep); ++mIt; for (; mIt != previouslyComputedMarkersOrdered.end(); ++mIt) { mv::Marker predictedMarker; if ( !t->mvState.PredictForward(mIt->frame, &predictedMarker) ) { break; } else { t->mvState.Update(*mIt); } } t->mvOptions = mvOptions; trackAndOptions.push_back(t); } /* Launch tracking in the scheduler thread. */ boost::shared_ptr<TrackArgs> args( new TrackArgs(start, end, frameStep, trackerNode->getApp()->getTimeLine(), viewer, trackContext, accessor, trackAndOptions, formatWidth, formatHeight, autoKeyingOnEnabledParamEnabled) ); _imp->scheduler->track(args); } // TrackerHelper::trackMarkers
bool TrackMarkerPM::trackMarker(bool forward, int refFrame, int frame) { KnobButtonPtr button; if (forward) { button = trackNextButton.lock(); } else { button = trackPrevButton.lock(); } KnobIntPtr refFrameK = refFrameKnob.lock(); refFrameK->setValue(refFrame); // Unslave the center knob since the trackerNode will update it, then update the marker center KnobDoublePtr center = centerKnob.lock(); center->unlink(DimSpec::all(), ViewSetSpec::all(), true); trackerNode->getEffectInstance()->onKnobValueChanged_public(button, eValueChangedReasonUserEdited, TimeValue(frame), ViewIdx(0)); KnobDoublePtr markerCenter = getCenterKnob(); // The TrackerPM plug-in has set a keyframe at the refFrame and frame, copy them bool ret = true; double centerPoint[2]; for (int i = 0; i < center->getNDimensions(); ++i) { { int index = center->getKeyFrameIndex(ViewIdx(0), DimIdx(i), TimeValue(frame)); if (index != -1) { centerPoint[i] = center->getValueAtTime(TimeValue(frame), DimIdx(i)); markerCenter->setValueAtTime(TimeValue(frame), centerPoint[i], ViewSetSpec::all(), DimIdx(i)); } else { // No keyframe at this time: tracking failed ret = false; break; } } { int index = center->getKeyFrameIndex(ViewIdx(0), DimIdx(i), TimeValue(refFrame)); if (index != -1) { double value = center->getValueAtTime(TimeValue(refFrame), DimIdx(i)); markerCenter->setValueAtTime(TimeValue(refFrame), value, ViewSetSpec::all(), DimIdx(i)); } } } // Convert the correlation score of the TrackerPM to the error if (ret) { KnobDoublePtr markerError = getErrorKnob(); KnobDoublePtr correlation = correlationScoreKnob.lock(); { int index = correlation->getKeyFrameIndex(ViewIdx(0), DimIdx(0), TimeValue(frame)); if (index != -1) { // The error is estimated as a percentage of the correlation across the number of pixels in the pattern window KnobDoublePtr pBtmLeft = patternBtmLeftKnob.lock(); KnobDoublePtr pTopRight = patternTopRightKnob.lock(); Point btmLeft, topRight; btmLeft.x = pBtmLeft->getValueAtTime(TimeValue(frame), DimIdx(0)); btmLeft.y = pBtmLeft->getValueAtTime(TimeValue(frame), DimIdx(1)); topRight.x = pTopRight->getValueAtTime(TimeValue(frame), DimIdx(0)); topRight.y = pTopRight->getValueAtTime(TimeValue(frame), DimIdx(1)); double areaPixels = (topRight.x - btmLeft.x) * (topRight.y - btmLeft.y); NodePtr trackerInput = trackerNode->getInput(0); if (trackerInput) { ImagePlaneDesc comps, paireComps; trackerInput->getEffectInstance()->getMetadataComponents(-1, &comps, &paireComps); areaPixels *= comps.getNumComponents(); } double value = correlation->getValueAtTime(TimeValue(frame), DimIdx(0)); // Convert to a percentage if (areaPixels > 0) { value /= areaPixels; } markerError->setValueAtTime(TimeValue(frame), value, ViewSetSpec::all(), DimIdx(0)); } } } if ( !center->linkTo(markerCenter) ) { throw std::runtime_error("Could not link center"); } return ret; } // TrackMarkerPM::trackMarker
void TrackMarker::resetCenter() { KnobItemsTablePtr model = getModel(); if (!model) { return; } RectD rod; NodePtr input = model->getNode()->getInput(0); if (!input) { Format f; getApp()->getProject()->getProjectDefaultFormat(&f); rod = f.toCanonicalFormat(); } else { TimeValue time(input->getApp()->getTimeLine()->currentFrame()); RenderScale scale(1.); RectD rod; { GetRegionOfDefinitionResultsPtr results; ActionRetCodeEnum stat = input->getEffectInstance()->getRegionOfDefinition_public(time, scale, ViewIdx(0), &results); if (!isFailureRetCode(stat)) { rod = results->getRoD(); } } Point center; center.x = 0; center.y = 0; center.x = (rod.x1 + rod.x2) / 2.; center.y = (rod.y1 + rod.y2) / 2.; KnobDoublePtr centerKnob = getCenterKnob(); centerKnob->setValue(center.x, ViewSetSpec::all(), DimIdx(0)); centerKnob->setValue(center.y, ViewSetSpec::all(), DimIdx(1)); } }
bool TrackMarker::isEnabled(TimeValue time) const { return _imp->enabled.lock()->getValueAtTime(time, DimIdx(0), ViewIdx(0), true); }