in dev/ParallaxView/ParallaxView.cpp [562:765]
void ParallaxView::UpdateExpressionAnimation(winrt::Orientation orientation)
{
if (SharedHelpers::IsTH2OrLower())
{
// The ParallaxView control is not supported on Windows versions prior to RS1.
return;
}
if (m_scrollInputHelper && m_scrollInputHelper->TargetElement() && m_scrollInputHelper->SourcePropertySet())
{
winrt::Visual targetVisual = winrt::ElementCompositionPreview::GetElementVisual(m_scrollInputHelper->TargetElement());
if (m_targetVisual != targetVisual)
{
m_targetVisual = targetVisual;
if (IsVisualTranslationPropertyAvailable())
{
winrt::ElementCompositionPreview::SetIsTranslationEnabled(m_scrollInputHelper->TargetElement(), true);
}
EnsureAnimatedVariables();
}
}
else if (m_targetVisual)
{
// Stop prior parallaxing animations.
m_targetVisual.StopAnimation(GetVisualTargetedPropertyName(winrt::Orientation::Horizontal));
m_targetVisual.StopAnimation(GetVisualTargetedPropertyName(winrt::Orientation::Vertical));
m_isHorizontalAnimationStarted = m_isVerticalAnimationStarted = false;
if (IsVisualTranslationPropertyAvailable())
{
m_targetVisual.Properties().InsertVector3(s_translationPropertyName, { 0.0f, 0.0f, 0.0f });
}
else
{
auto m = m_targetVisual.TransformMatrix();
m.m41 = m.m42 = 0.0f;
m_targetVisual.TransformMatrix(m);
}
m_targetVisual = nullptr;
}
if (m_targetVisual)
{
if ((orientation == winrt::Orientation::Horizontal && HorizontalShift() == 0.0) ||
(orientation == winrt::Orientation::Vertical && VerticalShift() == 0.0))
{
if (orientation == winrt::Orientation::Horizontal)
{
if (m_isHorizontalAnimationStarted)
{
// Stop prior horizontal parallaxing animation.
m_targetVisual.StopAnimation(GetVisualTargetedPropertyName(winrt::Orientation::Horizontal));
m_isHorizontalAnimationStarted = false;
if (IsVisualTranslationPropertyAvailable())
{
m_targetVisual.Properties().InsertVector3(s_translationPropertyName, { 0.0f, 0.0f, 0.0f });
}
else
{
auto m = m_targetVisual.TransformMatrix();
m.m41 = 0.0f;
m_targetVisual.TransformMatrix(m);
}
if (m_isVerticalAnimationStarted)
{
m_targetVisual.StartAnimation(GetVisualTargetedPropertyName(winrt::Orientation::Vertical), m_verticalParallaxExpressionInternal);
}
}
}
else if (m_isVerticalAnimationStarted)
{
// Stop prior vertical parallaxing animation.
m_targetVisual.StopAnimation(GetVisualTargetedPropertyName(winrt::Orientation::Vertical));
m_isVerticalAnimationStarted = false;
if (IsVisualTranslationPropertyAvailable())
{
m_targetVisual.Properties().InsertVector3(s_translationPropertyName, { 0.0f, 0.0f, 0.0f });
}
else
{
auto m = m_targetVisual.TransformMatrix();
m.m42 = 0.0f;
m_targetVisual.TransformMatrix(m);
}
if (m_isHorizontalAnimationStarted)
{
m_targetVisual.StartAnimation(GetVisualTargetedPropertyName(winrt::Orientation::Horizontal), m_horizontalParallaxExpressionInternal);
}
}
}
else
{
UpdateStartOffsetExpression(orientation);
UpdateEndOffsetExpression(orientation);
winrt::ExpressionAnimation parallaxExpressionInternal = (orientation == winrt::Orientation::Horizontal) ? m_horizontalParallaxExpressionInternal : m_verticalParallaxExpressionInternal;
std::wstring source = L"source." + static_cast<std::wstring>(m_scrollInputHelper->GetSourceOffsetPropertyName(orientation));
std::wstring startOffset = (orientation == winrt::Orientation::Horizontal) ? L"animatedVariables.HorizontalSourceStartOffset" : L"animatedVariables.VerticalSourceStartOffset";
std::wstring endOffset = (orientation == winrt::Orientation::Horizontal) ? L"animatedVariables.HorizontalSourceEndOffset" : L"animatedVariables.VerticalSourceEndOffset";
std::wstring parallaxExpression;
const float shift = (float)(orientation == winrt::Orientation::Horizontal ? HorizontalShift() : VerticalShift());
if ((orientation == winrt::Orientation::Horizontal && IsHorizontalShiftClamped()) ||
(orientation == winrt::Orientation::Vertical && IsVerticalShiftClamped()))
{
// Clamped parallax offset case.
if (shift > 0.0)
{
// X <= startOffset --> P(X) = 0
parallaxExpression = L"(-" + static_cast<std::wstring>(source) + L" <= " + static_cast<std::wstring>(startOffset) + L") ? 0.0f : ";
// startOffset < X < endOffset --> P(X) = -Min(MaxRatio, shift / (endOffset - startOffset)) * (X - startOffset)
parallaxExpression += L"((-" + static_cast<std::wstring>(source) + L" < " + static_cast<std::wstring>(endOffset) + L") ? ";
parallaxExpression += L"(-Min(maxRatio, (shift / (" + static_cast<std::wstring>(endOffset) + L" - " + static_cast<std::wstring>(startOffset) + L"))) * (-" + static_cast<std::wstring>(source) + L" - " + static_cast<std::wstring>(startOffset) + L")) : ";
// X >= endOffset --> P(X) = -Min(MaxRatio * Max(0 , endOffset - startOffset), shift)
parallaxExpression += L"-Min(maxRatio * Max(0.0f, " + static_cast<std::wstring>(endOffset) + L" - " + static_cast<std::wstring>(startOffset) + L"), shift))";
}
else
{
// shift < 0.0
// X <= startOffset --> P(X) = -Min(MaxRatio * Max(0 , endOffset - startOffset), -shift)
parallaxExpression = L"(-" + static_cast<std::wstring>(source) + L" <= " + static_cast<std::wstring>(startOffset) + L") ? -Min(maxRatio * Max(0.0f, " + static_cast<std::wstring>(endOffset) + L" - " + static_cast<std::wstring>(startOffset) + L"), -shift) : ";
// startOffset < X < endOffset --> P(X) = Min(MaxRatio, shift / (startOffset - endOffset)) * (X - endOffset)
parallaxExpression += L"((-" + static_cast<std::wstring>(source) + L" < " + static_cast<std::wstring>(endOffset) + L") ? ";
parallaxExpression += L"(Min(maxRatio, (shift / (" + static_cast<std::wstring>(startOffset) + L" - " + static_cast<std::wstring>(endOffset) + L"))) * (-" + static_cast<std::wstring>(source) + L" - " + static_cast<std::wstring>(endOffset) + L")) : ";
// X >= endOffset --> P(X) = 0
parallaxExpression += L"0.0f)";
}
}
else
{
// Unclamped parallax offset case.
if (shift > 0.0)
{
// startOffset == endOffset --> P(X) = 0
parallaxExpression = L"(" + static_cast<std::wstring>(startOffset) + L" == " + static_cast<std::wstring>(endOffset) + L") ? 0.0f : ";
// startOffset != endOffset --> P(X) = -Min(MaxRatio, shift / (endOffset - startOffset)) * (X - startOffset)
parallaxExpression += L"-Min(maxRatio, shift / (" + static_cast<std::wstring>(endOffset) + L" - " + static_cast<std::wstring>(startOffset) + L")) * (-" + static_cast<std::wstring>(source) + L" - " + static_cast<std::wstring>(startOffset) + L")";
}
else
{
// startOffset == endOffset --> P(X) = 0
parallaxExpression = L"(" + static_cast<std::wstring>(startOffset) + L" == " + static_cast<std::wstring>(endOffset) + L") ? 0.0f : ";
// startOffset != endOffset --> P(X) = Min(MaxRatio, shift / (startOffset - endOffset)) * (X - endOffset)
parallaxExpression += L"Min(maxRatio, shift / (" + static_cast<std::wstring>(startOffset) + L" - " + static_cast<std::wstring>(endOffset) + L")) * (-" + static_cast<std::wstring>(source) + L" - " + static_cast<std::wstring>(endOffset) + L")";
}
}
if (!parallaxExpressionInternal)
{
parallaxExpressionInternal = m_targetVisual.Compositor().CreateExpressionAnimation(parallaxExpression);
if (orientation == winrt::Orientation::Horizontal)
{
m_horizontalParallaxExpressionInternal = parallaxExpressionInternal;
}
else
{
m_verticalParallaxExpressionInternal = parallaxExpressionInternal;
}
}
else if (parallaxExpressionInternal.Expression() != parallaxExpression)
{
parallaxExpressionInternal.Expression(parallaxExpression);
}
parallaxExpressionInternal.SetReferenceParameter(L"source", m_scrollInputHelper->SourcePropertySet());
parallaxExpressionInternal.SetReferenceParameter(L"animatedVariables", m_animatedVariables);
parallaxExpressionInternal.SetScalarParameter(L"maxRatio", static_cast<float>(max(0.0, (orientation == winrt::Orientation::Horizontal ? MaxHorizontalShiftRatio() : MaxVerticalShiftRatio()))));
parallaxExpressionInternal.SetScalarParameter(L"shift", shift);
if (orientation == winrt::Orientation::Horizontal)
{
if (m_isHorizontalAnimationStarted)
{
m_targetVisual.StopAnimation(GetVisualTargetedPropertyName(winrt::Orientation::Horizontal));
}
m_targetVisual.StartAnimation(GetVisualTargetedPropertyName(winrt::Orientation::Horizontal), parallaxExpressionInternal);
m_isHorizontalAnimationStarted = true;
}
else
{
if (m_isVerticalAnimationStarted)
{
m_targetVisual.StopAnimation(GetVisualTargetedPropertyName(winrt::Orientation::Vertical));
}
m_targetVisual.StartAnimation(GetVisualTargetedPropertyName(winrt::Orientation::Vertical), parallaxExpressionInternal);
m_isVerticalAnimationStarted = true;
}
}
}
}