bool PointOverlayInteract::onOverlayPenDown(TimeValue time, const RenderScale & renderScale, ViewIdx view, const QPointF & viewportPos, const QPointF & penPos, double pressure, TimeValue timestamp, PenType /*pen*/) { 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; } _imp->lastPenPos = penPos; bool motion = onOverlayPenMotion(time, renderScale, view, viewportPos, penPos, pressure, timestamp); Q_UNUSED(motion); if (_imp->state == ePositionInteractStatePoised) { _imp->state = ePositionInteractStatePicked; _imp->interactiveDrag = _imp->getInteractive(); return true; } return false; }
void TrackMarker::resetCenter() { TrackerContextPtr context = getContext(); assert(context); NodePtr input = context->getNode()->getInput(0); if (input) { SequenceTime time = input->getApp()->getTimeLine()->currentFrame(); RenderScale scale; scale.x = scale.y = 1; RectD rod; bool isProjectFormat; StatusEnum stat = input->getEffectInstance()->getRegionOfDefinition_public(input->getHashValue(), time, scale, ViewIdx(0), &rod, &isProjectFormat); Point center; center.x = 0; center.y = 0; if (stat == eStatusOK) { center.x = (rod.x1 + rod.x2) / 2.; center.y = (rod.y1 + rod.y2) / 2.; } KnobDoublePtr centerKnob = getCenterKnob(); centerKnob->setValue(center.x, ViewSpec::current(), 0); centerKnob->setValue(center.y, ViewSpec::current(), 1); } }
void TrackMarker::resetTrack() { Point curCenter; KnobDoublePtr centerKnob = getCenterKnob(); curCenter.x = centerKnob->getValue(); curCenter.y = centerKnob->getValue(DimIdx(1)); const KnobsVec& knobs = getKnobs(); for (KnobsVec::const_iterator it = knobs.begin(); it != knobs.end(); ++it) { if (*it != centerKnob) { (*it)->resetToDefaultValue(DimSpec::all(), ViewSetSpec::all()); } else { (*it)->removeAnimation(ViewSetSpec::all(), DimSpec::all(), eValueChangedReasonUserEdited); std::vector<double> values(2); values[0] = curCenter.x; values[1] = curCenter.y; centerKnob->setValueAcrossDimensions(values); } } removeAnimation(ViewSetSpec::all(), DimSpec::all(), eValueChangedReasonUserEdited); }
void TrackMarker::resetTrack() { Point curCenter; KnobDoublePtr knob = getCenterKnob(); curCenter.x = knob->getValue(0); curCenter.y = knob->getValue(1); EffectInstancePtr effect = getContext()->getNode()->getEffectInstance(); effect->beginChanges(); const KnobsVec& knobs = getKnobs(); for (KnobsVec::const_iterator it = knobs.begin(); it != knobs.end(); ++it) { if (*it != knob) { for (int i = 0; i < (*it)->getDimension(); ++i) { (*it)->resetToDefaultValue(i); } } else { for (int i = 0; i < (*it)->getDimension(); ++i) { (*it)->removeAnimation(ViewSpec::current(), i); } knob->setValue(curCenter.x, ViewSpec::current(), 0); knob->setValue(curCenter.y, ViewSpec::current(), 1); } } effect->endChanges(); removeAllUserKeyframes(); }
QPointF ViewerNode::getWipeCenter() const { KnobDoublePtr wipeCenter = _imp->wipeCenter.lock(); QPointF r; r.rx() = wipeCenter->getValue(); r.ry() = wipeCenter->getValue(DimIdx(1)); return r; }
void TrackMarker::resetOffset() { KnobDoublePtr knob = getOffsetKnob(); for (int i = 0; i < knob->getDimension(); ++i) { knob->resetToDefaultValue(i); } }
void getTo(TimeValue time, int index, double* tx, double* ty) const { KnobDoublePtr knob = to[index].lock(); assert(knob); *tx = knob->getValueAtTime(time, DimIdx(0)); *ty = knob->getValueAtTime(time, DimIdx(1)); }
void ViewerNode::setUserRoI(const RectD& rect) { KnobDoublePtr btmLeft = _imp->userRoIBtmLeftKnob.lock(); KnobDoublePtr size = _imp->userRoISizeKnob.lock(); std::vector<double> values(2); values[0] = rect.x1; values[1] = rect.y1; btmLeft->setValueAcrossDimensions(values, DimIdx(0), ViewSetSpec::all(), eValueChangedReasonUserEdited); values[0] = rect.x2 - rect.x1; values[1] = rect.y2 - rect.y1; size->setValueAcrossDimensions(values, DimIdx(0), ViewSetSpec::all(), eValueChangedReasonUserEdited); }
void TrackArgs::getRedrawAreasNeeded(TimeValue time, std::list<RectD>* canonicalRects) const { for (std::vector<TrackMarkerAndOptionsPtr >::const_iterator it = _imp->tracks.begin(); it != _imp->tracks.end(); ++it) { if ( !(*it)->natronMarker->isEnabled(time) ) { continue; } KnobDoublePtr searchBtmLeft = (*it)->natronMarker->getSearchWindowBottomLeftKnob(); KnobDoublePtr searchTopRight = (*it)->natronMarker->getSearchWindowTopRightKnob(); KnobDoublePtr centerKnob = (*it)->natronMarker->getCenterKnob(); KnobDoublePtr offsetKnob = (*it)->natronMarker->getOffsetKnob(); Point offset, center, btmLeft, topRight; offset.x = offsetKnob->getValueAtTime(time, DimIdx(0)); offset.y = offsetKnob->getValueAtTime(time, DimIdx(1)); center.x = centerKnob->getValueAtTime(time, DimIdx(0)); center.y = centerKnob->getValueAtTime(time, DimIdx(1)); btmLeft.x = searchBtmLeft->getValueAtTime(time, DimIdx(0)) + center.x + offset.x; btmLeft.y = searchBtmLeft->getValueAtTime(time, DimIdx(1)) + center.y + offset.y; topRight.x = searchTopRight->getValueAtTime(time, DimIdx(0)) + center.x + offset.x; topRight.y = searchTopRight->getValueAtTime(time, DimIdx(1)) + center.y + offset.y; RectD rect; rect.x1 = btmLeft.x; rect.y1 = btmLeft.y; rect.x2 = topRight.x; rect.y2 = topRight.y; canonicalRects->push_back(rect); } }
RectI TrackMarker::getMarkerImageRoI(int time) const { const unsigned int mipmapLevel = 0; Point center, offset; KnobDoublePtr centerKnob = getCenterKnob(); KnobDoublePtr offsetKnob = getOffsetKnob(); center.x = centerKnob->getValueAtTime(time, 0); center.y = centerKnob->getValueAtTime(time, 1); offset.x = offsetKnob->getValueAtTime(time, 0); offset.y = offsetKnob->getValueAtTime(time, 1); RectD roiCanonical; KnobDoublePtr swBl = getSearchWindowBottomLeftKnob(); KnobDoublePtr swTr = getSearchWindowTopRightKnob(); roiCanonical.x1 = swBl->getValueAtTime(time, 0) + center.x + offset.x; roiCanonical.y1 = swBl->getValueAtTime(time, 1) + center.y + offset.y; roiCanonical.x2 = swTr->getValueAtTime(time, 0) + center.x + offset.x; roiCanonical.y2 = swTr->getValueAtTime(time, 1) + center.y + offset.y; RectI roi; NodePtr node = getContext()->getNode(); NodePtr input = node->getInput(0); if (!input) { return RectI(); } roiCanonical.toPixelEnclosing(mipmapLevel, input ? input->getEffectInstance()->getAspectRatio(-1) : 1., &roi); return roi; }
void TrackerNodePrivate::resetTransformParamsAnimation() { { // Revert animation on the corner pin KnobDoublePtr toPointsKnob[4]; KnobBoolPtr enabledPointsKnob[4]; for (int i = 0; i < 4; ++i) { toPointsKnob[i] = toPoints[i].lock(); enabledPointsKnob[i] = enableToPoint[i].lock(); } for (int i = 0; i < 4; ++i) { toPointsKnob[i]->resetToDefaultValue(DimSpec::all(), ViewSetSpec::all()); enabledPointsKnob[i]->resetToDefaultValue(DimSpec::all(), ViewSetSpec::all()); } } KnobDoublePtr centerKnob = center.lock(); centerKnob->resetToDefaultValue(DimSpec::all(), ViewSetSpec::all()); { // Revert animation on the transform KnobDoublePtr translationKnob = translate.lock(); KnobDoublePtr scaleKnob = scale.lock(); KnobDoublePtr rotationKnob = rotate.lock(); translationKnob->resetToDefaultValue(DimSpec::all(), ViewSetSpec::all()); scaleKnob->resetToDefaultValue(DimSpec::all(), ViewSetSpec::all()); rotationKnob->resetToDefaultValue(DimSpec::all(), ViewSetSpec::all()); } }
bool CornerPinOverlayInteract::onOverlayPenUp(TimeValue time, const RenderScale & /*renderScale*/, ViewIdx view, const QPointF & /*viewportPos*/, const QPointF & /*pos*/, double /*pressure*/, TimeValue /*timestamp*/) { // do not show interact if knob is secret or not enabled // see https://github.com/MrKepzie/Natron/issues/932 KnobDoublePtr from1Knob = _imp->from[0].lock(); if ( !from1Knob || !from1Knob->shouldDrawOverlayInteract() ) { return false; } bool didSomething = _imp->dragging != -1; if ( !_imp->interactiveDrag && (_imp->dragging != -1) ) { // no need to redraw overlay since it is slave to the paramaters if (_imp->useFromDrag) { KnobDoublePtr knob = _imp->from[_imp->dragging].lock(); assert(knob); std::vector<double> val(2); val[0] = _imp->fromDrag[_imp->dragging].x; val[1] = _imp->fromDrag[_imp->dragging].y; knob->setValueAcrossDimensions(val, DimIdx(0), view, eValueChangedReasonUserEdited); } else { KnobDoublePtr knob = _imp->to[_imp->dragging].lock(); assert(knob); std::vector<double> val(2); val[0] = _imp->toDrag[_imp->dragging].x; val[1] = _imp->toDrag[_imp->dragging].y; if (_imp->toPointsAutoKeyingEnabled) { knob->setValueAtTimeAcrossDimensions(time, val, DimIdx(0), view, eValueChangedReasonUserEdited); // Also set a keyframe on other points for (int i = 0; i < 4; ++i) { if (i == _imp->dragging) { continue; } std::vector<double> values(2); KnobDoublePtr toPoint = _imp->to[i].lock(); values[0] = toPoint->getValueAtTime(time, DimIdx(0)); values[1] = toPoint->getValueAtTime(time, DimIdx(1)); toPoint->setValueAtTimeAcrossDimensions(time, values, DimIdx(0), view, eValueChangedReasonUserEdited); } } else { knob->setValueAcrossDimensions(val, DimIdx(0), view, eValueChangedReasonUserEdited); } } } _imp->dragging = -1; return didSomething; } // onOverlayPenUp
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; }
bool PointOverlayInteract::onOverlayPenUp(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); bool didSomething = false; if (_imp->state == ePositionInteractStatePicked) { if (!_imp->interactiveDrag) { 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), view, eValueChangedReasonUserEdited); } _imp->state = ePositionInteractStateInactive; bool motion = onOverlayPenMotion(time, renderScale, view, viewportPos, penPos, pressure, timestamp); Q_UNUSED(motion); didSomething = true; } return didSomething; } // onOverlayPenUp
bool PointOverlayInteract::onOverlayFocusLost(TimeValue /*time*/, const RenderScale & /*renderScale*/, ViewIdx /*view*/) { 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; } if (_imp->state != ePositionInteractStateInactive) { _imp->state = ePositionInteractStateInactive; // state changed, must redraw redraw(); } return false; }
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)); } }
void TrackMarker::setKeyFrameOnCenterAndPatternAtTime(int time) { KnobDoublePtr center = _imp->center.lock(); for (int i = 0; i < center->getDimension(); ++i) { double v = center->getValueAtTime(time, i); center->setValueAtTime(time, v, ViewSpec::all(), i); } KnobDoublePtr patternCorners[4] = {_imp->patternBtmLeft.lock(), _imp->patternTopLeft.lock(), _imp->patternTopRight.lock(), _imp->patternBtmRight.lock()}; for (int c = 0; c < 4; ++c) { KnobDoublePtr k = patternCorners[c]; for (int i = 0; i < k->getDimension(); ++i) { double v = k->getValueAtTime(time, i); k->setValueAtTime(time, v, ViewSpec::all(), i); } } }
RectD ViewerNode::getUserRoI() const { RectD ret; KnobDoublePtr btmLeft = _imp->userRoIBtmLeftKnob.lock(); KnobDoublePtr size = _imp->userRoISizeKnob.lock(); ret.x1 = btmLeft->getValue(); ret.y1 = btmLeft->getValue(DimIdx(1)); ret.x2 = ret.x1 + size->getValue(); ret.y2 = ret.y1 + size->getValue(DimIdx(1)); return ret; }
RectD TrackMarker::getMarkerImageRoI(TimeValue time) const { Point center, offset; KnobDoublePtr centerKnob = getCenterKnob(); KnobDoublePtr offsetKnob = getOffsetKnob(); center.x = centerKnob->getValueAtTime(time, DimIdx(0)); center.y = centerKnob->getValueAtTime(time, DimIdx(1)); offset.x = offsetKnob->getValueAtTime(time, DimIdx(0)); offset.y = offsetKnob->getValueAtTime(time, DimIdx(1)); RectD roiCanonical; KnobDoublePtr swBl = getSearchWindowBottomLeftKnob(); KnobDoublePtr swTr = getSearchWindowTopRightKnob(); roiCanonical.x1 = swBl->getValueAtTime(time, DimIdx(0)) + center.x + offset.x; roiCanonical.y1 = swBl->getValueAtTime(time, DimIdx(1)) + center.y + offset.y; roiCanonical.x2 = swTr->getValueAtTime(time, DimIdx(0)) + center.x + offset.x; roiCanonical.y2 = swTr->getValueAtTime(time, DimIdx(1)) + center.y + offset.y; return roiCanonical; }
void TrackMarker::setKeyFrameOnCenterAndPatternAtTime(TimeValue time) { KnobDoublePtr center = _imp->center.lock(); { std::vector<double> values(2); values[0] = center->getValueAtTime(time); values[1] = center->getValueAtTime(time, DimIdx(1)); center->setValueAtTimeAcrossDimensions(time, values); } KnobDoublePtr patternCorners[4] = {_imp->patternBtmLeft.lock(), _imp->patternTopLeft.lock(), _imp->patternTopRight.lock(), _imp->patternBtmRight.lock()}; for (int c = 0; c < 4; ++c) { KnobDoublePtr k = patternCorners[c]; std::vector<double> values(2); values[0] = k->getValueAtTime(time, DimIdx(0)); values[1] = k->getValueAtTime(time, DimIdx(1)); k->setValueAcrossDimensions(values); } }
TEST_F(BaseTest, SetValues) { NodePtr generator = createNode(_generatorPluginID); assert(generator); KnobIPtr knob = generator->getKnobByName("noiseZSlope"); KnobDoublePtr radius = boost::dynamic_pointer_cast<KnobDouble>(knob); EXPECT_TRUE(radius != 0); if (!radius) { return; } radius->setValue(0.5); EXPECT_TRUE(radius->getValue() == 0.5); //Check that linear interpolation is working as intended KeyFrame kf; radius->setInterpolationAtTime(eCurveChangeReasonInternal, ViewSpec::all(), 0, 0, eKeyframeTypeLinear, &kf); radius->setValueAtTime(0, 0., ViewSpec::all(), 0); radius->setValueAtTime(100, 1., ViewSpec::all(), 0); for (int i = 0; i <= 100; ++i) { double v = radius->getValueAtTime(i); EXPECT_TRUE(std::abs(v - i / 100.) < 1e-6); } }
void TrackMarker::resetOffset() { KnobDoublePtr knob = getOffsetKnob(); knob->resetToDefaultValue(DimSpec::all(), ViewSetSpec::all()); }
void TrackMarker::initializeKnobs() { KnobItemsTablePtr model = getModel(); EffectInstancePtr effect; if (model) { effect = model->getNode()->getEffectInstance(); } KnobIntPtr defPatternSizeKnob, defSearchSizeKnob; KnobChoicePtr defMotionModelKnob; defPatternSizeKnob = toKnobInt(effect->getKnobByName(kTrackerUIParamDefaultMarkerPatternWinSize)); defSearchSizeKnob = toKnobInt(effect->getKnobByName(kTrackerUIParamDefaultMarkerSearchWinSize)); defMotionModelKnob = toKnobChoice(effect->getKnobByName(kTrackerUIParamDefaultMotionModel)); double patternHalfSize = defPatternSizeKnob ? defPatternSizeKnob->getValue() / 2. : 21; double searchHalfSize = defSearchSizeKnob ? defSearchSizeKnob->getValue() / 2. : 71; int defMotionModel_i = defMotionModelKnob ? defMotionModelKnob->getValue() : 0; KnobDoublePtr swbbtmLeft = createKnob<KnobDouble>(kTrackerParamSearchWndBtmLeft, 2); swbbtmLeft->setLabel(tr(kTrackerParamSearchWndBtmLeftLabel)); swbbtmLeft->setDefaultValue(-searchHalfSize, DimIdx(0)); swbbtmLeft->setDefaultValue(-searchHalfSize, DimIdx(1)); swbbtmLeft->setHintToolTip( tr(kTrackerParamSearchWndBtmLeftHint) ); _imp->searchWindowBtmLeft = swbbtmLeft; KnobDoublePtr swbtRight = createKnob<KnobDouble>(kTrackerParamSearchWndTopRight, 2); swbtRight->setLabel(tr(kTrackerParamSearchWndTopRightLabel)); swbtRight->setDefaultValue(searchHalfSize, DimIdx(0)); swbtRight->setDefaultValue(searchHalfSize, DimIdx(1)); swbtRight->setHintToolTip( tr(kTrackerParamSearchWndTopRightHint) ); _imp->searchWindowTopRight = swbtRight; KnobDoublePtr ptLeft = createKnob<KnobDouble>(kTrackerParamPatternTopLeft, 2); ptLeft->setLabel(tr(kTrackerParamPatternTopLeftLabel)); ptLeft->setDefaultValue(-patternHalfSize, DimIdx(0)); ptLeft->setDefaultValue(patternHalfSize, DimIdx(1)); ptLeft->setHintToolTip( tr(kTrackerParamPatternTopLeftHint) ); _imp->patternTopLeft = ptLeft; KnobDoublePtr ptRight = createKnob<KnobDouble>(kTrackerParamPatternTopRight, 2); ptRight->setLabel(tr(kTrackerParamPatternTopRightLabel)); ptRight->setDefaultValue(patternHalfSize, DimIdx(0)); ptRight->setDefaultValue(patternHalfSize, DimIdx(1)); ptRight->setHintToolTip( tr(kTrackerParamPatternTopRightHint) ); _imp->patternTopRight = ptRight; KnobDoublePtr pBRight = createKnob<KnobDouble>(kTrackerParamPatternBtmRight, 2); pBRight->setLabel(tr(kTrackerParamPatternBtmRightLabel)); pBRight->setDefaultValue(patternHalfSize, DimIdx(0)); pBRight->setDefaultValue(-patternHalfSize, DimIdx(1)); pBRight->setHintToolTip( tr(kTrackerParamPatternBtmRightHint) ); _imp->patternBtmRight = pBRight; KnobDoublePtr pBLeft = createKnob<KnobDouble>(kTrackerParamPatternBtmLeft, 2); pBLeft->setLabel(tr(kTrackerParamPatternBtmLeftLabel)); pBLeft->setDefaultValue(-patternHalfSize, DimIdx(0)); pBLeft->setDefaultValue(-patternHalfSize, DimIdx(1)); pBLeft->setHintToolTip( tr(kTrackerParamPatternBtmLeftHint) ); _imp->patternBtmLeft = pBLeft; KnobDoublePtr centerKnob = createKnob<KnobDouble>(kTrackerParamCenter, 2); centerKnob->setLabel(tr(kTrackerParamCenterLabel)); centerKnob->setHintToolTip( tr(kTrackerParamCenterHint) ); _imp->center = centerKnob; KnobDoublePtr offsetKnob = createKnob<KnobDouble>(kTrackerParamOffset, 2); offsetKnob->setLabel(tr(kTrackerParamOffsetLabel)); offsetKnob->setHintToolTip( tr(kTrackerParamOffsetHint) ); _imp->offset = offsetKnob; #ifdef NATRON_TRACK_MARKER_USE_WEIGHT KnobDoublePtr weightKnob = createKnob<KnobDouble>(kTrackerParamTrackWeight, 1); weightKnob->setLabel(tr(kTrackerParamTrackWeightLabel)); weightKnob->setHintToolTip( tr(kTrackerParamTrackWeightHint) ); weightKnob->setDefaultValue(1.); weightKnob->setAnimationEnabled(false); weightKnob->setRange(0., 1.); _imp->weight = weightKnob; #endif KnobChoicePtr mmodelKnob = createKnob<KnobChoice>(kTrackerParamMotionModel, 1); mmodelKnob->setHintToolTip( tr(kTrackerParamMotionModelHint) ); mmodelKnob->setLabel(tr(kTrackerParamMotionModelLabel)); { std::vector<ChoiceOption> choices, helps; std::map<int, std::string> icons; TrackerNodePrivate::getMotionModelsAndHelps(true, &choices, &icons); mmodelKnob->populateChoices(choices); mmodelKnob->setIcons(icons); } mmodelKnob->setDefaultValue(defMotionModel_i); _imp->motionModel = mmodelKnob; KnobDoublePtr errKnob = createKnob<KnobDouble>(kTrackerParamError, 1); errKnob->setLabel(tr(kTrackerParamErrorLabel)); _imp->error = errKnob; KnobBoolPtr enableKnob = createKnob<KnobBool>(kTrackerParamEnabled, 1); enableKnob->setLabel(tr(kTrackerParamEnabledLabel)); enableKnob->setHintToolTip( tr(kTrackerParamEnabledHint) ); enableKnob->setAnimationEnabled(true); enableKnob->setDefaultValue(true); _imp->enabled = enableKnob; addColumn(kKnobTableItemColumnLabel, DimIdx(0)); addColumn(kTrackerParamEnabled, DimIdx(0)); addColumn(kTrackerParamMotionModel, DimIdx(0)); addColumn(kTrackerParamCenter, DimIdx(0)); addColumn(kTrackerParamCenter, DimIdx(1)); addColumn(kTrackerParamOffset, DimIdx(0)); addColumn(kTrackerParamOffset, DimIdx(1)); addColumn(kTrackerParamError, DimIdx(0)); } // TrackMarker::initializeKnobs
void TrackMarkerPM::initializeKnobs() { TrackMarker::initializeKnobs(); NodePtr thisNode = getModel()->getNode(); NodePtr node; { CreateNodeArgsPtr args(CreateNodeArgs::create( PLUGINID_OFX_TRACKERPM, NodeCollectionPtr() )); args->setProperty<bool>(kCreateNodeArgsPropVolatile, true); args->setProperty<bool>(kCreateNodeArgsPropNoNodeGUI, true); args->setProperty<std::string>(kCreateNodeArgsPropNodeInitialName, "TrackerPMNode"); node = getApp()->createNode(args); if (!node) { throw std::runtime_error("Couldn't create plug-in " PLUGINID_OFX_TRACKERPM); } if (thisNode) { NodePtr inputNode = thisNode->getInput(0); if (inputNode) { node->connectInput(inputNode, 0); } } trackerNode = node; } KnobItemsTablePtr model = getModel(); EffectInstancePtr effect; if (model) { effect = model->getNode()->getEffectInstance(); } trackPrevButton = getNodeKnob<KnobButton>(node, kTrackerPMParamTrackingPrevious); trackNextButton = getNodeKnob<KnobButton>(node, kTrackerPMParamTrackingNext); KnobDoublePtr center = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingCenterPoint); centerKnob = center; // Slave the center knob and unslave when tracking if ( !center->linkTo(getCenterKnob()) ) { throw std::runtime_error("Could not link center"); } KnobDoublePtr offset = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingOffset); // Slave the offset knob if ( !offset->linkTo( getOffsetKnob() ) ) { throw std::runtime_error("Could not link offset"); } offsetKnob = offset; // Ref frame is set for each refFrameKnob = getNodeKnob<KnobInt>(node, kTrackerPMParamTrackingReferenceFrame); // Enable reference frame KnobBoolPtr enableRefFrameKnob = getNodeKnob<KnobBool>(node, kTrackerPMParamTrackingEnableReferenceFrame); enableRefFrameKnob->setValue(true); KnobChoicePtr scoreType = getNodeKnob<KnobChoice>(node, kTrackerPMParamScore); if (effect) { #ifdef kTrackerParamPatternMatchingScoreType KnobIPtr modelKnob = effect->getKnobByName(kTrackerParamPatternMatchingScoreType); if (modelKnob) { if ( !scoreType->linkTo(modelKnob) ) { throw std::runtime_error("Could not link scoreType"); } } #endif } scoreTypeKnob = scoreType; KnobDoublePtr correlationScore = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingCorrelationScore); correlationScoreKnob = correlationScore; KnobDoublePtr patternBtmLeft = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingPatternBoxBtmLeft); patternBtmLeftKnob = patternBtmLeft; // Slave the search window and pattern of the node to the parameters of the marker (void)patternBtmLeft->linkTo(getPatternBtmLeftKnob()); KnobDoublePtr patternTopRight = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingPatternBoxTopRight); patternTopRightKnob = patternTopRight; (void)patternTopRight->linkTo(getPatternTopRightKnob()); KnobDoublePtr searchWindowBtmLeft = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingSearchBoxBtmLeft); searchWindowBtmLeftKnob = searchWindowBtmLeft; (void)searchWindowBtmLeft->linkTo(getSearchWindowBottomLeftKnob()); KnobDoublePtr searchWindowTopRight = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingSearchBoxTopRight); searchWindowTopRightKnob = searchWindowTopRight; (void)searchWindowTopRight->linkTo(getSearchWindowTopRightKnob()); } // TrackMarkerPM::initializeKnobs
void TrackerNodePrivate::computeTransformParamsFromTracksEnd(double refTime, double maxFittingError, const QList<TransformData>& results) { QList<TransformData> validResults; for (QList<TransformData>::const_iterator it = results.begin(); it != results.end(); ++it) { if (it->valid) { validResults.push_back(*it); } } KnobIntPtr smoothKnob = smoothTransform.lock(); int smoothTJitter, smoothRJitter, smoothSJitter; smoothTJitter = smoothKnob->getValue(DimIdx(0)); smoothRJitter = smoothKnob->getValue(DimIdx(1)); smoothSJitter = smoothKnob->getValue(DimIdx(2)); KnobDoublePtr translationKnob = translate.lock(); KnobDoublePtr scaleKnob = scale.lock(); KnobDoublePtr rotationKnob = rotate.lock(); KnobDoublePtr fittingErrorKnob = fittingError.lock(); KnobStringPtr fittingWarningKnob = fittingErrorWarning.lock(); int halfTJitter = smoothTJitter / 2; int halfRJitter = smoothRJitter / 2; int halfSJitter = smoothSJitter / 2; translationKnob->blockValueChanges(); scaleKnob->blockValueChanges(); rotationKnob->blockValueChanges(); fittingErrorKnob->blockValueChanges(); std::list<KnobIPtr> animatedKnobsChanged; animatedKnobsChanged.push_back(translationKnob); animatedKnobsChanged.push_back(scaleKnob); animatedKnobsChanged.push_back(rotationKnob); animatedKnobsChanged.push_back(fittingErrorKnob); Curve tmpTXCurve, tmpTYCurve, tmpRotateCurve, tmpScaleCurve, tmpFittingErrorCurve; bool mustShowFittingWarn = false; for (QList<TransformData>::const_iterator itResults = validResults.begin(); itResults != validResults.end(); ++itResults) { const TransformData& dataAtTime = *itResults; { KeyFrame kf(dataAtTime.time, dataAtTime.rms); if (dataAtTime.rms >= maxFittingError) { mustShowFittingWarn = true; } tmpFittingErrorCurve.setOrAddKeyframe(kf); } if (!dataAtTime.hasRotationAndScale) { // no rotation or scale: simply extract the translation Point translation; if (smoothTJitter > 1) { TranslateData avgT; averageDataFunctor<QList<TransformData>::const_iterator, void, TranslateData>(validResults.begin(), validResults.end(), itResults, halfTJitter, 0, &avgT, 0); translation.x = avgT.p.x; translation.y = avgT.p.y; } else { translation.x = dataAtTime.translation.x; translation.y = dataAtTime.translation.y; } { KeyFrame kx(dataAtTime.time, translation.x); KeyFrame ky(dataAtTime.time, translation.y); tmpTXCurve.setOrAddKeyframe(kx); tmpTYCurve.setOrAddKeyframe(ky); } } else { double rot = 0; if (smoothRJitter > 1) { RotateData avgR; averageDataFunctor<QList<TransformData>::const_iterator, void, RotateData>(validResults.begin(), validResults.end(), itResults, halfRJitter, 0, &avgR, 0); rot = avgR.r; } else { rot = dataAtTime.rotation; } { KeyFrame k(dataAtTime.time, rot); tmpRotateCurve.setOrAddKeyframe(k); } double scale; if (smoothSJitter > 1) { ScaleData avgR; averageDataFunctor<QList<TransformData>::const_iterator, void, ScaleData>(validResults.begin(), validResults.end(), itResults, halfSJitter, 0, &avgR, 0); scale = avgR.s; } else { scale = dataAtTime.scale; } { KeyFrame k(dataAtTime.time, scale); tmpScaleCurve.setOrAddKeyframe(k); } Point translation; if (smoothTJitter > 1) { TranslateData avgT; averageDataFunctor<QList<TransformData>::const_iterator, void, TranslateData>(validResults.begin(), validResults.end(), itResults, halfTJitter, 0, &avgT, 0); translation.x = avgT.p.x; translation.y = avgT.p.y; } else { translation.x = dataAtTime.translation.x; translation.y = dataAtTime.translation.y; } { KeyFrame kx(dataAtTime.time, translation.x); KeyFrame ky(dataAtTime.time, translation.y); tmpTXCurve.setOrAddKeyframe(kx); tmpTYCurve.setOrAddKeyframe(ky); } } } // for all samples fittingWarningKnob->setSecret(!mustShowFittingWarn); fittingErrorKnob->cloneCurve(ViewIdx(0), DimIdx(0), tmpFittingErrorCurve, 0 /*offset*/, 0 /*range*/); translationKnob->cloneCurve(ViewIdx(0), DimIdx(0), tmpTXCurve, 0 /*offset*/, 0 /*range*/); translationKnob->cloneCurve(ViewIdx(0), DimIdx(1), tmpTYCurve, 0 /*offset*/, 0 /*range*/); rotationKnob->cloneCurve(ViewIdx(0), DimIdx(0), tmpRotateCurve, 0 /*offset*/, 0 /*range*/); scaleKnob->cloneCurve(ViewIdx(0), DimIdx(0), tmpScaleCurve, 0 /*offset*/, 0 /*range*/); scaleKnob->cloneCurve(ViewIdx(0), DimIdx(1), tmpScaleCurve, 0 /*offset*/, 0 /*range*/); for (std::list<KnobIPtr>::iterator it = animatedKnobsChanged.begin(); it != animatedKnobsChanged.end(); ++it) { (*it)->unblockValueChanges(); (*it)->evaluateValueChange(DimSpec::all(), TimeValue(refTime), ViewSetSpec::all(), eValueChangedReasonUserEdited); } endSolve(); } // TrackerNodePrivate::computeTransformParamsFromTracksEnd
void TrackerNodePrivate::exportTrackDataFromExportOptions() { //bool transformLink = _imp->exportLink.lock()->getValue(); KnobChoicePtr transformTypeKnob = transformType.lock(); assert(transformTypeKnob); int transformType_i = transformTypeKnob->getValue(); TrackerTransformNodeEnum transformType = (TrackerTransformNodeEnum)transformType_i; KnobChoicePtr motionTypeKnob = motionType.lock(); if (!motionTypeKnob) { return; } int motionType_i = motionTypeKnob->getValue(); TrackerMotionTypeEnum mt = (TrackerMotionTypeEnum)motionType_i; if (mt == eTrackerMotionTypeNone) { Dialogs::errorDialog( tr("Tracker Export").toStdString(), tr("Please select the export mode with the Motion Type parameter").toStdString() ); return; } bool linked = exportLink.lock()->getValue(); QString pluginID; switch (transformType) { case eTrackerTransformNodeCornerPin: pluginID = QString::fromUtf8(PLUGINID_OFX_CORNERPIN); break; case eTrackerTransformNodeTransform: pluginID = QString::fromUtf8(PLUGINID_OFX_TRANSFORM); break; } NodePtr thisNode = publicInterface->getNode(); AppInstancePtr app = thisNode->getApp(); CreateNodeArgsPtr args(CreateNodeArgs::create( pluginID.toStdString(), thisNode->getGroup() )); args->setProperty<bool>(kCreateNodeArgsPropAutoConnect, false); args->setProperty<bool>(kCreateNodeArgsPropSettingsOpened, false); NodePtr createdNode = app->createNode(args); if (!createdNode) { return; } // Move the new node double thisNodePos[2]; double thisNodeSize[2]; thisNode->getPosition(&thisNodePos[0], &thisNodePos[1]); thisNode->getSize(&thisNodeSize[0], &thisNodeSize[1]); createdNode->setPosition(thisNodePos[0] + thisNodeSize[0] * 2., thisNodePos[1]); TimeValue timeForFromPoints(referenceFrame.lock()->getValue()); switch (transformType) { case eTrackerTransformNodeCornerPin: { KnobDoublePtr cornerPinToPoints[4]; KnobDoublePtr cornerPinFromPoints[4]; for (unsigned int i = 0; i < 4; ++i) { cornerPinFromPoints[i] = getCornerPinPoint(createdNode, true, i); assert(cornerPinFromPoints[i]); for (int j = 0; j < cornerPinFromPoints[i]->getNDimensions(); ++j) { cornerPinFromPoints[i]->setValue(fromPoints[i].lock()->getValueAtTime(timeForFromPoints, DimIdx(j)), ViewSetSpec::all(), DimIdx(j)); } cornerPinToPoints[i] = getCornerPinPoint(createdNode, false, i); assert(cornerPinToPoints[i]); if (!linked) { cornerPinToPoints[i]->copyKnob( toPoints[i].lock() ); } else { bool ok = cornerPinToPoints[i]->linkTo(toPoints[i].lock()); (void)ok; assert(ok); } } { KnobIPtr knob = createdNode->getKnobByName(kCornerPinParamMatrix); if (knob) { KnobDoublePtr isType = toKnobDouble(knob); if (isType) { isType->copyKnob(cornerPinMatrix.lock() ); } } } break; } case eTrackerTransformNodeTransform: { KnobIPtr translateKnob = createdNode->getKnobByName(kTransformParamTranslate); if (translateKnob) { KnobDoublePtr isDbl = toKnobDouble(translateKnob); if (isDbl) { if (!linked) { isDbl->copyKnob(translate.lock() ); } else { ignore_result(isDbl->linkTo(translate.lock())); } } } KnobIPtr scaleKnob = createdNode->getKnobByName(kTransformParamScale); if (scaleKnob) { KnobDoublePtr isDbl = toKnobDouble(scaleKnob); if (isDbl) { if (!linked) { isDbl->copyKnob(scale.lock() ); } else { ignore_result(isDbl->linkTo(scale.lock())); } } } KnobIPtr rotateKnob = createdNode->getKnobByName(kTransformParamRotate); if (rotateKnob) { KnobDoublePtr isDbl = toKnobDouble(rotateKnob); if (isDbl) { if (!linked) { isDbl->copyKnob(rotate.lock()); } else { ignore_result(isDbl->linkTo(rotate.lock())); } } } KnobIPtr centerKnob = createdNode->getKnobByName(kTransformParamCenter); if (centerKnob) { KnobDoublePtr isDbl = toKnobDouble(centerKnob); if (isDbl) { isDbl->copyKnob( center.lock() ); } } break; } } // switch KnobIPtr cpInvertKnob = createdNode->getKnobByName(kTransformParamInvert); if (cpInvertKnob) { KnobBoolPtr isBool = toKnobBool(cpInvertKnob); if (isBool) { if (!linked) { isBool->copyKnob(invertTransform.lock()); } else { ignore_result(isBool->linkTo(invertTransform.lock())); } } } { KnobIPtr knob = createdNode->getKnobByName(kTransformParamMotionBlur); if (knob) { KnobDoublePtr isType = toKnobDouble(knob); if (isType) { isType->copyKnob(motionBlur.lock()); } } } { KnobIPtr knob = createdNode->getKnobByName(kTransformParamShutter); if (knob) { KnobDoublePtr isType = toKnobDouble(knob); if (isType) { isType->copyKnob(shutter.lock()); } } } { KnobIPtr knob = createdNode->getKnobByName(kTransformParamShutterOffset); if (knob) { KnobChoicePtr isType = toKnobChoice(knob); if (isType) { isType->copyKnob(shutterOffset.lock()); } } } { KnobIPtr knob = createdNode->getKnobByName(kTransformParamCustomShutterOffset); if (knob) { KnobDoublePtr isType = toKnobDouble(knob); if (isType) { isType->copyKnob(customShutterOffset.lock()); } } } } // exportTrackDataFromExportOptions
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 ViewerNodeOverlay::drawWipeControl() { Point pixelScale; getPixelScale(pixelScale.x, pixelScale.y); double angle; QPointF center; double mixAmount; { angle = _imp->wipeAngle.lock()->getValue(); KnobDoublePtr centerKnob = _imp->wipeCenter.lock(); center.rx() = centerKnob->getValue(); center.ry() = centerKnob->getValue(DimIdx(1)); mixAmount = _imp->wipeAmount.lock()->getValue(); } double alphaMix1, alphaMix0, alphaCurMix; alphaMix1 = angle + M_PI_4 / 2; alphaMix0 = angle + 3. * M_PI_4 / 2; alphaCurMix = mixAmount * (alphaMix1 - alphaMix0) + alphaMix0; QPointF mix0Pos, mixPos, mix1Pos; double mixX, mixY, rotateW, rotateH, rotateOffsetX, rotateOffsetY; mixX = WIPE_MIX_HANDLE_LENGTH * pixelScale.x; mixY = WIPE_MIX_HANDLE_LENGTH * pixelScale.y; rotateW = WIPE_ROTATE_HANDLE_LENGTH * pixelScale.x; rotateH = WIPE_ROTATE_HANDLE_LENGTH * pixelScale.y; rotateOffsetX = WIPE_ROTATE_OFFSET * pixelScale.x; rotateOffsetY = WIPE_ROTATE_OFFSET * pixelScale.y; mixPos.setX(center.x() + std::cos(alphaCurMix) * mixX); mixPos.setY(center.y() + std::sin(alphaCurMix) * mixY); mix0Pos.setX(center.x() + std::cos(alphaMix0) * mixX); mix0Pos.setY(center.y() + std::sin(alphaMix0) * mixY); mix1Pos.setX(center.x() + std::cos(alphaMix1) * mixX); mix1Pos.setY(center.y() + std::sin(alphaMix1) * mixY); QPointF oppositeAxisBottom, oppositeAxisTop, rotateAxisLeft, rotateAxisRight; rotateAxisRight.setX( center.x() + std::cos(angle) * (rotateW - rotateOffsetX) ); rotateAxisRight.setY( center.y() + std::sin(angle) * (rotateH - rotateOffsetY) ); rotateAxisLeft.setX(center.x() - std::cos(angle) * rotateOffsetX); rotateAxisLeft.setY( center.y() - (std::sin(angle) * rotateOffsetY) ); oppositeAxisTop.setX( center.x() + std::cos(angle + M_PI_2) * (rotateW / 2.) ); oppositeAxisTop.setY( center.y() + std::sin(angle + M_PI_2) * (rotateH / 2.) ); oppositeAxisBottom.setX( center.x() - std::cos(angle + M_PI_2) * (rotateW / 2.) ); oppositeAxisBottom.setY( center.y() - std::sin(angle + M_PI_2) * (rotateH / 2.) ); { GLProtectAttrib<GL_GPU> a(GL_ENABLE_BIT | GL_LINE_BIT | GL_CURRENT_BIT | GL_HINT_BIT | GL_TRANSFORM_BIT | GL_COLOR_BUFFER_BIT); //GLProtectMatrix p(GL_PROJECTION); // useless (we do two glTranslate in opposite directions) // Draw everything twice // l = 0: shadow // l = 1: drawing double baseColor[3]; for (int l = 0; l < 2; ++l) { // shadow (uses GL_PROJECTION) GL_GPU::MatrixMode(GL_PROJECTION); int direction = (l == 0) ? 1 : -1; // translate (1,-1) pixels GL_GPU::Translated(direction * pixelScale.x, -direction * pixelScale.y, 0); GL_GPU::MatrixMode(GL_MODELVIEW); // Modelview should be used on Nuke if (l == 0) { // Draw a shadow for the cross hair baseColor[0] = baseColor[1] = baseColor[2] = 0.; } else { baseColor[0] = baseColor[1] = baseColor[2] = 0.8; } GL_GPU::Enable(GL_BLEND); GL_GPU::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_GPU::Enable(GL_LINE_SMOOTH); GL_GPU::Hint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE); GL_GPU::LineWidth(1.5); GL_GPU::Begin(GL_LINES); if ( (hoverState == eHoverStateWipeRotateHandle) || (uiState == eViewerNodeInteractMouseStateRotatingWipeHandle) ) { GL_GPU::Color4f(0., 1. * l, 0., 1.); } GL_GPU::Color4f(baseColor[0], baseColor[1], baseColor[2], 1.); GL_GPU::Vertex2d( rotateAxisLeft.x(), rotateAxisLeft.y() ); GL_GPU::Vertex2d( rotateAxisRight.x(), rotateAxisRight.y() ); GL_GPU::Vertex2d( oppositeAxisBottom.x(), oppositeAxisBottom.y() ); GL_GPU::Vertex2d( oppositeAxisTop.x(), oppositeAxisTop.y() ); GL_GPU::Vertex2d( center.x(), center.y() ); GL_GPU::Vertex2d( mixPos.x(), mixPos.y() ); GL_GPU::End(); GL_GPU::LineWidth(1.); ///if hovering the rotate handle or dragging it show a small bended arrow if ( (hoverState == eHoverStateWipeRotateHandle) || (uiState == eViewerNodeInteractMouseStateRotatingWipeHandle) ) { GLProtectMatrix<GL_GPU> p(GL_MODELVIEW); GL_GPU::Color4f(0., 1. * l, 0., 1.); double arrowCenterX = WIPE_ROTATE_HANDLE_LENGTH * pixelScale.x / 2; ///draw an arrow slightly bended. This is an arc of circle of radius 5 in X, and 10 in Y. OfxPointD arrowRadius; arrowRadius.x = 5. * pixelScale.x; arrowRadius.y = 10. * pixelScale.y; GL_GPU::Translatef(center.x(), center.y(), 0.); GL_GPU::Rotatef(angle * 180.0 / M_PI, 0, 0, 1); // center the oval at x_center, y_center GL_GPU::Translatef (arrowCenterX, 0., 0); // draw the oval using line segments GL_GPU::Begin (GL_LINE_STRIP); GL_GPU::Vertex2f (0, arrowRadius.y); GL_GPU::Vertex2f (arrowRadius.x, 0.); GL_GPU::Vertex2f (0, -arrowRadius.y); GL_GPU::End (); GL_GPU::Begin(GL_LINES); ///draw the top head GL_GPU::Vertex2f(0., arrowRadius.y); GL_GPU::Vertex2f(0., arrowRadius.y - arrowRadius.x ); GL_GPU::Vertex2f(0., arrowRadius.y); GL_GPU::Vertex2f(4. * pixelScale.x, arrowRadius.y - 3. * pixelScale.y); // 5^2 = 3^2+4^2 ///draw the bottom head GL_GPU::Vertex2f(0., -arrowRadius.y); GL_GPU::Vertex2f(0., -arrowRadius.y + 5. * pixelScale.y); GL_GPU::Vertex2f(0., -arrowRadius.y); GL_GPU::Vertex2f(4. * pixelScale.x, -arrowRadius.y + 3. * pixelScale.y); // 5^2 = 3^2+4^2 GL_GPU::End(); GL_GPU::Color4f(baseColor[0], baseColor[1], baseColor[2], 1.); } GL_GPU::PointSize(5.); GL_GPU::Enable(GL_POINT_SMOOTH); GL_GPU::Begin(GL_POINTS); GL_GPU::Vertex2d( center.x(), center.y() ); if ( ( (hoverState == eHoverStateWipeMix) && (uiState != eViewerNodeInteractMouseStateRotatingWipeHandle) ) || (uiState == eViewerNodeInteractMouseStateDraggingWipeMixHandle) ) { GL_GPU::Color4f(0., 1. * l, 0., 1.); } GL_GPU::Vertex2d( mixPos.x(), mixPos.y() ); GL_GPU::End(); GL_GPU::PointSize(1.); drawArcOfCircle(center, mixX, mixY, angle + M_PI_4 / 2, angle + 3. * M_PI_4 / 2); } } // GLProtectAttrib a(GL_ENABLE_BIT | GL_LINE_BIT | GL_CURRENT_BIT | GL_HINT_BIT | GL_TRANSFORM_BIT | GL_COLOR_BUFFER_BIT); } // drawWipeControl
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 ViewerNodeOverlay::onOverlayPenMotion(TimeValue /*time*/, const RenderScale & /*renderScale*/, ViewIdx /*view*/, const QPointF & /*viewportPos*/, const QPointF & pos, double /*pressure*/, TimeValue /*timestamp*/) { Point pixelScale; getPixelScale(pixelScale.x, pixelScale.y); bool userRoIEnabled = _imp->toggleUserRoIButtonKnob.lock()->getValue(); RectD userRoI; if (userRoIEnabled) { if (uiState == eViewerNodeInteractMouseStateDraggingRoiBottomEdge || uiState == eViewerNodeInteractMouseStateDraggingRoiTopEdge || uiState == eViewerNodeInteractMouseStateDraggingRoiLeftEdge || uiState == eViewerNodeInteractMouseStateDraggingRoiRightEdge || uiState == eViewerNodeInteractMouseStateDraggingRoiCross || uiState == eViewerNodeInteractMouseStateDraggingRoiBottomLeft || uiState == eViewerNodeInteractMouseStateDraggingRoiBottomRight || uiState == eViewerNodeInteractMouseStateDraggingRoiTopLeft || uiState == eViewerNodeInteractMouseStateDraggingRoiTopRight) { userRoI = draggedUserRoI; } else { userRoI = _imp->_publicInterface->getUserRoI(); } } bool wipeEnabled = (ViewerCompositingOperatorEnum)_imp->blendingModeChoiceKnob.lock()->getValue() != eViewerCompositingOperatorNone; double wipeAmount = _imp->_publicInterface->getWipeAmount(); double wipeAngle = _imp->_publicInterface->getWipeAngle(); QPointF wipeCenter = _imp->_publicInterface->getWipeCenter(); bool wasHovering = hoverState != eHoverStateNothing; bool cursorSet = false; bool overlayCaught = false; hoverState = eHoverStateNothing; if ( wipeEnabled && isNearbyWipeCenter(wipeCenter, pos, pixelScale.x, pixelScale.y) ) { _imp->_publicInterface->setCurrentCursor(eCursorSizeAll); cursorSet = true; } else if ( wipeEnabled && isNearbyWipeMixHandle(wipeCenter, wipeAngle, wipeAmount, pos, pixelScale.x, pixelScale.y) ) { hoverState = eHoverStateWipeMix; overlayCaught = true; } else if ( wipeEnabled && isNearbyWipeRotateBar(wipeCenter, wipeAngle, pos, pixelScale.x, pixelScale.y) ) { hoverState = eHoverStateWipeRotateHandle; overlayCaught = true; } else if (userRoIEnabled) { if ( isNearbyUserRoIBottomEdge(userRoI, pos, pixelScale.x, pixelScale.y) || isNearbyUserRoITopEdge(userRoI, pos, pixelScale.x, pixelScale.y) || ( uiState == eViewerNodeInteractMouseStateDraggingRoiBottomEdge) || ( uiState == eViewerNodeInteractMouseStateDraggingRoiTopEdge) ) { _imp->_publicInterface->setCurrentCursor(eCursorSizeVer); cursorSet = true; } else if ( isNearbyUserRoILeftEdge(userRoI, pos, pixelScale.x, pixelScale.y) || isNearbyUserRoIRightEdge(userRoI, pos, pixelScale.x, pixelScale.y) || ( uiState == eViewerNodeInteractMouseStateDraggingRoiLeftEdge) || ( uiState == eViewerNodeInteractMouseStateDraggingRoiRightEdge) ) { _imp->_publicInterface->setCurrentCursor(eCursorSizeHor); cursorSet = true; } else if ( isNearbyUserRoI( (userRoI.x1 + userRoI.x2) / 2, (userRoI.y1 + userRoI.y2) / 2, pos, pixelScale.x, pixelScale.y ) || ( uiState == eViewerNodeInteractMouseStateDraggingRoiCross) ) { _imp->_publicInterface->setCurrentCursor(eCursorSizeAll); cursorSet = true; } else if ( isNearbyUserRoI(userRoI.x2, userRoI.y1, pos, pixelScale.x, pixelScale.y) || isNearbyUserRoI(userRoI.x1, userRoI.y2, pos, pixelScale.x, pixelScale.y) || ( uiState == eViewerNodeInteractMouseStateDraggingRoiBottomRight) || ( uiState == eViewerNodeInteractMouseStateDraggingRoiTopLeft) ) { _imp->_publicInterface->setCurrentCursor(eCursorFDiag); cursorSet = true; } else if ( isNearbyUserRoI(userRoI.x1, userRoI.y1, pos, pixelScale.x, pixelScale.y) || isNearbyUserRoI(userRoI.x2, userRoI.y2, pos, pixelScale.x, pixelScale.y) || ( uiState == eViewerNodeInteractMouseStateDraggingRoiBottomLeft) || ( uiState == eViewerNodeInteractMouseStateDraggingRoiTopRight) ) { _imp->_publicInterface->setCurrentCursor(eCursorBDiag); cursorSet = true; } } if (!cursorSet) { _imp->_publicInterface->setCurrentCursor(eCursorDefault); } if ( (hoverState == eHoverStateNothing) && wasHovering ) { overlayCaught = true; } double dx = pos.x() - lastMousePos.x(); double dy = pos.y() - lastMousePos.y(); switch (uiState) { case eViewerNodeInteractMouseStateDraggingRoiBottomEdge: { if ( (draggedUserRoI.y1 + dy) < draggedUserRoI.y2 ) { draggedUserRoI.y1 += dy; overlayCaught = true; } break; } case eViewerNodeInteractMouseStateDraggingRoiLeftEdge: { if ( (draggedUserRoI.x1 + dx) < draggedUserRoI.x2 ) { draggedUserRoI.x1 += dx; overlayCaught = true; } break; } case eViewerNodeInteractMouseStateDraggingRoiRightEdge: { if ( (draggedUserRoI.x2 + dx) > draggedUserRoI.x1 ) { draggedUserRoI.x2 += dx; overlayCaught = true; } break; } case eViewerNodeInteractMouseStateDraggingRoiTopEdge: { if ( (draggedUserRoI.y2 + dy) > draggedUserRoI.y1 ) { draggedUserRoI.y2 += dy; overlayCaught = true; } break; } case eViewerNodeInteractMouseStateDraggingRoiCross: { draggedUserRoI.translate(dx, dy); overlayCaught = true; break; } case eViewerNodeInteractMouseStateDraggingRoiTopLeft: { if ( (draggedUserRoI.y2 + dy) > draggedUserRoI.y1 ) { draggedUserRoI.y2 += dy; } if ( (draggedUserRoI.x1 + dx) < draggedUserRoI.x2 ) { draggedUserRoI.x1 += dx; } overlayCaught = true; break; } case eViewerNodeInteractMouseStateDraggingRoiTopRight: { if ( (draggedUserRoI.y2 + dy) > draggedUserRoI.y1 ) { draggedUserRoI.y2 += dy; } if ( (draggedUserRoI.x2 + dx) > draggedUserRoI.x1 ) { draggedUserRoI.x2 += dx; } overlayCaught = true; break; } case eViewerNodeInteractMouseStateDraggingRoiBottomRight: case eViewerNodeInteractMouseStateBuildingUserRoI:{ if ( (draggedUserRoI.x2 + dx) > draggedUserRoI.x1 ) { draggedUserRoI.x2 += dx; } if ( (draggedUserRoI.y1 + dy) < draggedUserRoI.y2 ) { draggedUserRoI.y1 += dy; } overlayCaught = true; break; } case eViewerNodeInteractMouseStateDraggingRoiBottomLeft: { if ( (draggedUserRoI.y1 + dy) < draggedUserRoI.y2 ) { draggedUserRoI.y1 += dy; } if ( (draggedUserRoI.x1 + dx) < draggedUserRoI.x2 ) { draggedUserRoI.x1 += dx; } overlayCaught = true; break; } case eViewerNodeInteractMouseStateDraggingWipeCenter: { KnobDoublePtr centerKnob = _imp->wipeCenter.lock(); centerKnob->setValue(centerKnob->getValue() + dx); centerKnob->setValue(centerKnob->getValue(DimIdx(1)) + dy, ViewSetSpec::all(), DimIdx(1)); overlayCaught = true; break; } case eViewerNodeInteractMouseStateDraggingWipeMixHandle: { KnobDoublePtr centerKnob = _imp->wipeCenter.lock(); Point center; center.x = centerKnob->getValue(); center.y = centerKnob->getValue(DimIdx(1)); double angle = std::atan2( pos.y() - center.y, pos.x() - center.x ); double prevAngle = std::atan2( lastMousePos.y() - center.y, lastMousePos.x() - center.x ); KnobDoublePtr mixKnob = _imp->wipeAmount.lock(); double mixAmount = mixKnob->getValue(); mixAmount -= (angle - prevAngle); mixAmount = std::max( 0., std::min(mixAmount, 1.) ); mixKnob->setValue(mixAmount); overlayCaught = true; break; } case eViewerNodeInteractMouseStateRotatingWipeHandle: { KnobDoublePtr centerKnob = _imp->wipeCenter.lock(); Point center; center.x = centerKnob->getValue(); center.y = centerKnob->getValue(DimIdx(1)); double angle = std::atan2( pos.y() - center.y, pos.x() - center.x ); KnobDoublePtr angleKnob = _imp->wipeAngle.lock(); double closestPI2 = M_PI_2 * std::floor(angle / M_PI_2 + 0.5); if (std::fabs(angle - closestPI2) < 0.1) { // snap to closest multiple of PI / 2. angle = closestPI2; } angleKnob->setValue(angle); overlayCaught = true; break; } default: break; } lastMousePos = pos; return overlayCaught; } // onOverlayPenMotion