mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-09 23:34:20 +00:00
Direct2D: Fix gradient fill when the brush is transformed with not just translation
The code contains a performance optimisation for cases where the world transform is translation only. In this case instead of applying the brush transformation first and then the world translation, the order is reversed. The translation is applied first and then the brush transformation. Flipping the transformations however is only correct in the special case when both transformations are translation only.
This commit is contained in:
parent
bb5a9cbac9
commit
35fe3ac714
2 changed files with 80 additions and 1 deletions
|
|
@ -469,7 +469,7 @@ public:
|
|||
{
|
||||
if ((flags & BrushTransformFlags::applyWorldTransform) != 0)
|
||||
{
|
||||
if (currentTransform.isOnlyTranslated)
|
||||
if (currentTransform.isOnlyTranslated && fillType.transform.isOnlyTranslation())
|
||||
translation = currentTransform.offset.toFloat();
|
||||
else
|
||||
transform = currentTransform.getTransform();
|
||||
|
|
|
|||
|
|
@ -1380,6 +1380,12 @@ public:
|
|||
|
||||
compareImages (targetNative, targetSoftware, 1, pixelsToIgnore);
|
||||
}
|
||||
|
||||
beginTest ("Gradient fill transform should compose with world transform correctly");
|
||||
{
|
||||
testGradientFillTransform (1.0f);
|
||||
testGradientFillTransform (1.5f);
|
||||
}
|
||||
}
|
||||
|
||||
static Image createEdgeMask (int sourceWidth,
|
||||
|
|
@ -1433,6 +1439,79 @@ public:
|
|||
const auto averageError = (double) accumulatedError / (double) numSamples;
|
||||
expect (std::abs (averageError) < 1.0 && maxAbsError < 10);
|
||||
}
|
||||
|
||||
void testGradientFillTransform (float scale)
|
||||
{
|
||||
constexpr int size = 500;
|
||||
constexpr int circleSize = 100;
|
||||
constexpr int brushTranslation = 20;
|
||||
|
||||
Image image { Image::RGB,
|
||||
roundToInt (size * scale),
|
||||
roundToInt (size * scale),
|
||||
true };
|
||||
|
||||
{
|
||||
for (int i = 0; i < size / circleSize; ++i)
|
||||
{
|
||||
Graphics g { image };
|
||||
|
||||
g.addTransform (AffineTransform::scale (scale));
|
||||
g.addTransform (AffineTransform::translation ((float) i * circleSize, (float) i * circleSize));
|
||||
|
||||
const auto fillCol1 { Colours::red };
|
||||
const auto fillCol2 { Colours::green };
|
||||
const auto centreLoc = circleSize / 2.0f;
|
||||
|
||||
FillType innerGlowGrad = ColourGradient { fillCol1,
|
||||
{ centreLoc, centreLoc },
|
||||
fillCol2,
|
||||
{ centreLoc, 0.0f },
|
||||
true };
|
||||
|
||||
innerGlowGrad.gradient->addColour (0.19, fillCol1);
|
||||
|
||||
innerGlowGrad.transform = AffineTransform::scale (1.1f, 0.9f, centreLoc, centreLoc)
|
||||
.followedBy (AffineTransform::translation (brushTranslation,
|
||||
brushTranslation));
|
||||
|
||||
g.setFillType (innerGlowGrad);
|
||||
g.fillEllipse (0, 0, (float) circleSize, (float) circleSize);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < size / circleSize; ++i)
|
||||
{
|
||||
const auto getScaled = [scale] (Point<int> p)
|
||||
{
|
||||
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 };
|
||||
|
||||
const auto redPosition = getScaled (centre + brushOffset);
|
||||
expect (image.getPixelAt (redPosition.getX(), redPosition.getY()) == Colours::red);
|
||||
|
||||
const auto mostlyRedPosition = getScaled (centre);
|
||||
expect (approximatelyEqual (image.getPixelAt (mostlyRedPosition.getX(), mostlyRedPosition.getY()),
|
||||
Colour { 138, 59, 0 }));
|
||||
|
||||
const auto greenPosition = getScaled (centre.withY (2));
|
||||
expect (image.getPixelAt (greenPosition.getX(), greenPosition.getY()) == Colours::green);
|
||||
|
||||
const auto blackPosition = getScaled ({ circleSize - 2, 2 });
|
||||
expect (image.getPixelAt (blackPosition.getX(), blackPosition.getY()) == Colours::black);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static Direct2DGraphicsContextTests direct2DGraphicsContextTests;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue