MCGR: Adapted GradientAxial to make use of MCGR

Added to make GradientAxial work using the MCGR
as 2nd of six types. This one was complicated
since it uses the gradient(s) 'reversed' when you
look at it, from outside to inside. Had to do
quite some tickeling to get it all work, but
looks good now.

For modifyBColor I Could re-use the started
tooling as planned.

To get the reverse usage working I ended up in
1st adapting the previous usage to make more use
of std::iterator and reverse_iterator to be able
to use the reversed state of the ColorSteps more
'controlled' as if trying to adapt the numerical
indices to the vector (that ended in chaos).

It is still 100% backward-compatible, so as long
as there is no source using this it will stay
invisible - by purpose.

Tests look good with this one, see the static
variable nUseGradientSteps.

Change-Id: I0117ec9a24b5e55869b3e2741c67fb87b549db97
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147510
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
This commit is contained in:
Armin Le Grand (allotropia) 2023-02-23 11:22:31 +01:00 committed by Armin Le Grand
parent bddc275d1e
commit 94cdbfb931
2 changed files with 74 additions and 65 deletions

View file

@ -467,7 +467,7 @@ namespace basegfx
{
const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV);
// Ignore Y, this is not needed at all for Y-Oriented gradients
// Ignore X, this is not needed at all for Y-Oriented gradients
// if(aCoor.getX() < 0.0 || aCoor.getX() > 1.0)
// {
// return 0.0;
@ -483,13 +483,6 @@ namespace basegfx
return 1.0; // end value for outside
}
// const sal_uInt32 nSteps(rGradInfo.getRequestedSteps());
// if(nSteps)
// {
// return floor(aCoor.getY() * nSteps) / double(nSteps - 1);
// }
return aCoor.getY();
}
@ -497,7 +490,7 @@ namespace basegfx
{
const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV);
// Ignore Y, this is not needed at all for Y-Oriented gradients
// Ignore X, this is not needed at all for Y-Oriented gradients
//if(aCoor.getX() < 0.0 || aCoor.getX() > 1.0)
//{
// return 0.0;
@ -510,13 +503,6 @@ namespace basegfx
return 1.0; // use end value when outside in Y
}
const sal_uInt32 nSteps(rGradInfo.getRequestedSteps());
if(nSteps)
{
return floor(fAbsY * nSteps) / double(nSteps - 1);
}
return fAbsY;
}

View file

@ -138,18 +138,13 @@ namespace drawinglayer::texture
if (mnColorSteps.empty())
return;
// get start color and also cc to rOuterColor
basegfx::BColor aCStart(mnColorSteps[0].getColor());
rOuterColor = aCStart;
// fill in return parameter rOuterColor before returning
rOuterColor = mnColorSteps.front().getColor();
// only one color, done
if (mnColorSteps.size() < 2)
return;
// here we could check that fOffsetStart == mnColorSteps[0].getOffset(),
// but just assume/correct that StartColor is at 0.0
double fOffsetStart(0.0 /*mnColorSteps[0].getOffset()*/);
// prepare unit range transform
basegfx::B2DHomMatrix aPattern;
@ -161,14 +156,19 @@ namespace drawinglayer::texture
aPattern.scale(mfUnitWidth, 1.0);
aPattern.translate(mfUnitMinX, 0.0);
for (size_t outerLoop(1); outerLoop < mnColorSteps.size(); outerLoop++)
// outer loop over ColorSteps, each is from cs_l to cs_r
for (auto cs_l(mnColorSteps.begin()), cs_r(cs_l + 1); cs_r != mnColorSteps.end(); cs_l++, cs_r++)
{
const basegfx::BColor aCEnd(mnColorSteps[outerLoop].getColor());
// get colors & calculate steps
const basegfx::BColor aCStart(cs_l->getColor());
const basegfx::BColor aCEnd(cs_r->getColor());
const sal_uInt32 nSteps(basegfx::utils::calculateNumberOfSteps(
maGradientInfo.getRequestedSteps(), aCStart, aCEnd));
const double fOffsetEnd(mnColorSteps[outerLoop].getOffset());
// get offsets & calculate StripeWidth
// nSteps is >= 1, see getRequestedSteps, so no check needed here
const double fOffsetStart(cs_l->getOffset());
const double fOffsetEnd(cs_r->getOffset());
const double fStripeWidth((fOffsetEnd - fOffsetStart) / nSteps);
// for the 1st color range we do not need to create the 1st step
@ -177,7 +177,7 @@ namespace drawinglayer::texture
// colored using rOuterColor.
// We *need* to create this though for all 'inner' color ranges
// to get a correct start
const sal_uInt32 nStartInnerLoop(1 == outerLoop ? 1 : 0);
const sal_uInt32 nStartInnerLoop(cs_l == mnColorSteps.begin() ? 1 : 0);
for (sal_uInt32 innerLoop(nStartInnerLoop); innerLoop < nSteps; innerLoop++)
{
@ -205,9 +205,6 @@ namespace drawinglayer::texture
aB2DHomMatrixAndBColor.maBColor = interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1));
rEntries.push_back(aB2DHomMatrixAndBColor);
}
aCStart = aCEnd;
fOffsetStart = fOffsetEnd;
}
}
@ -264,59 +261,85 @@ namespace drawinglayer::texture
std::vector< B2DHomMatrixAndBColor >& rEntries,
basegfx::BColor& rOuterColor)
{
if(mnColorSteps.size() <= 1)
// no color at all, done
if (mnColorSteps.empty())
return;
const basegfx::BColor maStart(mnColorSteps.front().getColor());
const basegfx::BColor maEnd(mnColorSteps.back().getColor());
const sal_uInt32 nSteps(basegfx::utils::calculateNumberOfSteps(
maGradientInfo.getRequestedSteps(), maStart, maEnd));
// fill in return parameter rOuterColor before returning
// CAUTION: for GradientAxial the color range is inverted (!)
rOuterColor = mnColorSteps.back().getColor();
rOuterColor = maEnd;
const double fStripeWidth(1.0 / nSteps);
B2DHomMatrixAndBColor aB2DHomMatrixAndBColor;
// only one color, done
if (mnColorSteps.size() < 2)
return;
for(sal_uInt32 a(1); a < nSteps; a++)
// prepare unit range transform
basegfx::B2DHomMatrix aPattern;
// bring in X from unit circle [-1, -1, 1, 1] to unit range [0, 0, 1, 1]
aPattern.scale(0.5, 1.0);
aPattern.translate(0.5, 0.0);
// scale/translate in X
aPattern.scale(mfUnitWidth, 1.0);
aPattern.translate(mfUnitMinX, 0.0);
// outer loop over ColorSteps, each is from cs_l to cs_r
// CAUTION: for GradientAxial the color range is used inverted (!)
// thus, to loop backward, use rbegin/rend
for (auto cs_r(mnColorSteps.rbegin()), cs_l(cs_r + 1); cs_l != mnColorSteps.rend(); cs_l++, cs_r++)
{
const double fPos(fStripeWidth * a);
basegfx::B2DHomMatrix aNew;
// get colors & calculate steps
const basegfx::BColor aCStart(cs_l->getColor());
const basegfx::BColor aCEnd(cs_r->getColor());
const sal_uInt32 nSteps(basegfx::utils::calculateNumberOfSteps(
maGradientInfo.getRequestedSteps(), aCStart, aCEnd));
// bring in X from unit circle [-1, -1, 1, 1] to unit range [0, 0, 1, 1]
aNew.scale(0.5, 1.0);
aNew.translate(0.5, 0.0);
// get offsets & calculate StripeWidth
// nSteps is >= 1, see getRequestedSteps, so no check needed here
const double fOffsetStart(cs_l->getOffset());
const double fOffsetEnd(cs_r->getOffset());
const double fStripeWidth((fOffsetEnd - fOffsetStart) / nSteps);
// scale/translate in X
aNew.scale(mfUnitWidth, 1.0);
aNew.translate(mfUnitMinX, 0.0);
// for the 1st color range we do not need to create the 1st step, see above
const sal_uInt32 nStartInnerLoop(cs_r == mnColorSteps.rbegin() ? 1 : 0);
// already centered in Y on X-Axis, just scale in Y
aNew.scale(1.0, 1.0 - fPos);
for (sal_uInt32 innerLoop(nStartInnerLoop); innerLoop < nSteps; innerLoop++)
{
// calculate pos in Y
const double fPos(fOffsetEnd - (fStripeWidth * innerLoop));
// set at target
aB2DHomMatrixAndBColor.maB2DHomMatrix = maGradientInfo.getTextureTransform() * aNew;
// already centered in Y on X-Axis, just scale in Y
basegfx::B2DHomMatrix aNew(aPattern);
aNew.scale(1.0, fPos);
// interpolate and set color
aB2DHomMatrixAndBColor.maBColor = interpolate(maEnd, maStart, double(a) / double(nSteps - 1));
// set and add at target
B2DHomMatrixAndBColor aB2DHomMatrixAndBColor;
rEntries.push_back(aB2DHomMatrixAndBColor);
aB2DHomMatrixAndBColor.maB2DHomMatrix = maGradientInfo.getTextureTransform() * aNew;
aB2DHomMatrixAndBColor.maBColor = interpolate(aCEnd, aCStart, double(innerLoop) / double(nSteps - 1));
rEntries.push_back(aB2DHomMatrixAndBColor);
}
}
}
void GeoTexSvxGradientAxial::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const
{
if(mnColorSteps.size() <= 1)
{
rBColor = mnColorSteps.front().getColor();
}
else
{
const double fScaler(basegfx::utils::getAxialGradientAlpha(rUV, maGradientInfo));
// no color at all, done
if (mnColorSteps.empty())
return;
const basegfx::BColor maStart(mnColorSteps.front().getColor());
const basegfx::BColor maEnd(mnColorSteps.back().getColor());
rBColor = basegfx::interpolate(maStart, maEnd, fScaler);
// just single color, done
if (mnColorSteps.size() < 2)
{
// CAUTION: for GradientAxial the color range is used inverted (!)
rBColor = mnColorSteps.back().getColor();
return;
}
// texture-back-transform X/Y -> t [0.0..1.0] and determine color
const double fScaler(basegfx::utils::getAxialGradientAlpha(rUV, maGradientInfo));
rBColor = basegfx::utils::modifyBColor(mnColorSteps, fScaler, mnRequestedSteps);
}