1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-09 23:34:20 +00:00

Direct2D: Always call SetTransform for gradient/image brushes

This partly reverts commit ad28684b10.
Prior to that change, getBrush() would always end up calling
SetTransform on gradient/image brushes. This is important because, when
drawing text, we combine the current brush transform with the text
transform. If we don't reset the brush transform each time, these
transforms end up accumulating across frames.
This commit is contained in:
reuk 2025-09-08 14:08:51 +01:00
parent 17df2b8037
commit 641497918c
No known key found for this signature in database
2 changed files with 72 additions and 25 deletions

View file

@ -471,19 +471,8 @@ public:
if (fillType.isGradient())
{
auto p1 = fillType.gradient->point1;
auto p2 = fillType.gradient->point2;
if (transform.isOnlyTranslation())
{
Point<float> translation { transform.getTranslationX(), transform.getTranslationY() };
p1 += translation;
p2 += translation;
}
else
{
currentBrush->SetTransform (D2DUtilities::transformToMatrix (transform));
}
const auto p1 = fillType.gradient->point1;
const auto p2 = fillType.gradient->point2;
if (fillType.gradient->isRadial)
{
@ -498,11 +487,8 @@ public:
linearGradient->SetEndPoint ({ p2.x, p2.y });
}
}
else
{
currentBrush->SetTransform (D2DUtilities::transformToMatrix (transform));
}
currentBrush->SetTransform (D2DUtilities::transformToMatrix (transform));
currentBrush->SetOpacity (fillType.getOpacity());
return currentBrush;

View file

@ -1386,6 +1386,13 @@ public:
testGradientFillTransform (1.0f);
testGradientFillTransform (1.5f);
}
beginTest ("Text gradient fill transform should compose with world transform correctly");
{
testTextGradientFillTransform (2.0f);
testTextGradientFillTransform (1.5f);
testTextGradientFillTransform (1.0f);
}
}
static Image createEdgeMask (int sourceWidth,
@ -1487,14 +1494,6 @@ public:
return p.toFloat().transformedBy (AffineTransform::scale (scale)).roundToInt();
};
const auto approximatelyEqual = [] (const Colour& a, const Colour& b)
{
return std::abs (a.getRed() - b.getRed()) < 2
&& std::abs (a.getGreen() - b.getGreen()) < 2
&& std::abs (a.getBlue() - b.getBlue()) < 2
&& std::abs (a.getAlpha() - b.getAlpha()) < 2;
};
const Point<int> centre { circleSize / 2, circleSize / 2 };
const Point<int> brushOffset { brushTranslation, brushTranslation };
@ -1512,6 +1511,68 @@ public:
expect (image.getPixelAt (blackPosition.getX(), blackPosition.getY()) == Colours::black);
}
}
void testTextGradientFillTransform (float scale)
{
const auto typeface = loadTypeface (FontBinaryData::Karla_Regular_Typo_Off_Offsets_Off);
constexpr int size = 500;
Image image { Image::RGB,
roundToInt (size * scale),
roundToInt (size * scale),
true };
const auto fillCol1 = Colours::cyan;
const auto fillCol2 = Colours::magenta;
const auto fillColMiddle = fillCol1.interpolatedWith (fillCol2, 0.5f);
{
Graphics g { image };
g.addTransform (AffineTransform::scale (scale));
g.setFont (FontOptions { typeface }.withPointHeight (50));
g.setGradientFill ({ fillCol1, { size * 0.5f - 80, 0 }, fillCol2, { size * 0.5f + 80, 0.0f }, false });
for (auto i = 0; i != 10; ++i)
{
g.drawText (String::repeatedString ("-", 100),
Rectangle { size * 2, size }.translated (i * 50 - 500, i * 50),
Justification::topLeft,
false);
}
}
const auto getPixelAtScaled = [&image, scale] (Point<int> p)
{
const auto scaled = p.toFloat().transformedBy (AffineTransform::scale (scale)).roundToInt();
return image.getPixelAt (scaled.x, scaled.y);
};
expect (approximatelyEqual (getPixelAtScaled ({ 15, 27 }), fillCol1));
expect (approximatelyEqual (getPixelAtScaled ({ 485, 27 }), fillCol2));
expect (approximatelyEqual (getPixelAtScaled ({ 15, 77 }), fillCol1));
expect (approximatelyEqual (getPixelAtScaled ({ 485, 77 }), fillCol2));
expect (approximatelyEqual (getPixelAtScaled ({ 250, 77 }), fillColMiddle));
expect (approximatelyEqual (getPixelAtScaled ({ 15, 477 }), fillCol1));
expect (approximatelyEqual (getPixelAtScaled ({ 485, 477 }), fillCol2));
expect (approximatelyEqual (getPixelAtScaled ({ 250, 477 }), fillColMiddle));
}
static bool approximatelyEqual (const Colour& a, const Colour& b)
{
return std::abs (a.getRed() - b.getRed()) < 2
&& std::abs (a.getGreen() - b.getGreen()) < 2
&& std::abs (a.getBlue() - b.getBlue()) < 2
&& std::abs (a.getAlpha() - b.getAlpha()) < 2;
}
static Typeface::Ptr loadTypeface (Span<const unsigned char> data)
{
return Typeface::createSystemTypefaceFor (data.data(), data.size());
}
};
static Direct2DGraphicsContextTests direct2DGraphicsContextTests;