bool AnimationModule::findItem(QTreeWidgetItem* treeItem, AnimatedItemTypeEnum *type, KnobAnimPtr* isKnob, TableItemAnimPtr* isTableItem, NodeAnimPtr* isNodeItem, ViewSetSpec* view, DimSpec* dimension) const { assert(treeItem && type && isKnob && isTableItem && isNodeItem && view && dimension); if (!treeItem) { return false; } void* ptr = treeItem->data(0, QT_ROLE_CONTEXT_ITEM_POINTER).value<void*>(); if (!ptr) { return false; } *type = (AnimatedItemTypeEnum)treeItem->data(0, QT_ROLE_CONTEXT_TYPE).toInt(); switch (*type) { case eAnimatedItemTypeCommon: case eAnimatedItemTypeFrameRange: case eAnimatedItemTypeGroup: case eAnimatedItemTypeReader: case eAnimatedItemTypeRetime: case eAnimatedItemTypeTimeOffset: *isNodeItem = ((NodeAnim*)ptr)->shared_from_this(); break; case eAnimatedItemTypeKnobDim: case eAnimatedItemTypeKnobRoot: case eAnimatedItemTypeKnobView: *isKnob = toKnobAnim(((AnimItemBase*)ptr)->shared_from_this()); break; case eAnimatedItemTypeTableItemAnimation: case eAnimatedItemTypeTableItemRoot: *isTableItem = toTableItemAnim(((AnimItemBase*)ptr)->shared_from_this()); break; } *view = ViewSetSpec(treeItem->data(0, QT_ROLE_CONTEXT_VIEW).toInt()); *dimension = DimSpec(treeItem->data(0, QT_ROLE_CONTEXT_DIM).toInt()); return true; } // findItem
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
void ViewerNode::setZoomComboBoxText(const std::string& text) { ChoiceOption opt(text, "", ""); _imp->zoomChoiceKnob.lock()->setActiveEntry(opt, ViewSetSpec(0), eValueChangedReasonPluginEdited); }
bool PointOverlayInteract::onOverlayPenMotion(TimeValue time, const RenderScale & /*renderScale*/, ViewIdx view, const QPointF & /*viewportPos*/, const QPointF & penPos, double /*pressure*/, TimeValue /*timestamp*/) { KnobDoublePtr knob = _imp->param.lock(); // do not show interact if knob is secret or not enabled // see https://github.com/MrKepzie/Natron/issues/932 if ( !knob || !knob->shouldDrawOverlayInteract() ) { return false; } RenderScale pscale; getPixelScale(pscale.x, pscale.y); QPointF pos; if (_imp->state == ePositionInteractStatePicked) { pos = _imp->lastPenPos; } else { double p[2]; for (int i = 0; i < 2; ++i) { p[i] = knob->getValueAtTime(time, DimIdx(i)); if (knob->getValueIsNormalized(DimIdx(i)) != eValueIsNormalizedNone) { p[i] = knob->denormalize(DimIdx(i), time, p[i]); } } pos.setX(p[0]); pos.setY(p[1]); } bool didSomething = false; bool valuesChanged = false; switch (_imp->state) { case ePositionInteractStateInactive: case ePositionInteractStatePoised: { // are we in the box, become 'poised' PositionInteractState newState; if ( ( std::fabs( penPos.x() - pos.x() ) <= _imp->pointTolerance() * pscale.x) && ( std::fabs( penPos.y() - pos.y() ) <= _imp->pointTolerance() * pscale.y) ) { newState = ePositionInteractStatePoised; } else { newState = ePositionInteractStateInactive; } if (_imp->state != newState) { // state changed, must redraw redraw(); } _imp->state = newState; //} break; } case ePositionInteractStatePicked: { valuesChanged = true; break; } } didSomething = (_imp->state == ePositionInteractStatePoised) || (_imp->state == ePositionInteractStatePicked); if ( (_imp->state != ePositionInteractStateInactive) && _imp->interactiveDrag && valuesChanged ) { std::vector<double> p(2); p[0] = fround(_imp->lastPenPos.x(), pscale.x); p[1] = fround(_imp->lastPenPos.y(), pscale.y); for (int i = 0; i < 2; ++i) { if (knob->getValueIsNormalized(DimIdx(i)) != eValueIsNormalizedNone) { p[i] = knob->normalize(DimIdx(i), time, p[i]); } } knob->setValueAcrossDimensions(p, DimIdx(0), ViewSetSpec(view), eValueChangedReasonUserEdited); } _imp->lastPenPos = penPos; return (didSomething || valuesChanged); } // onOverlayPenMotion