mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-14 12:04:29 +00:00
renderer/sw_engine: support the focal property in the radial gradient.
@Issue: https://github.com/thorvg/thorvg/issues/1558
This commit is contained in:
parent
7430589586
commit
ce3c11838c
8 changed files with 369 additions and 306 deletions
|
@ -29,11 +29,9 @@ source_file = [
|
|||
'tvgFill.cpp',
|
||||
'tvgGlCanvas.cpp',
|
||||
'tvgInitializer.cpp',
|
||||
'tvgLinearGradient.cpp',
|
||||
'tvgLoader.cpp',
|
||||
'tvgPaint.cpp',
|
||||
'tvgPicture.cpp',
|
||||
'tvgRadialGradient.cpp',
|
||||
'tvgRender.cpp',
|
||||
'tvgSaver.cpp',
|
||||
'tvgScene.cpp',
|
||||
|
|
|
@ -139,10 +139,11 @@ struct SwFill
|
|||
};
|
||||
|
||||
struct SwRadial {
|
||||
float a11, a12, shiftX;
|
||||
float a21, a22, shiftY;
|
||||
float detSecDeriv;
|
||||
float a;
|
||||
float a11, a12, a13;
|
||||
float a21, a22, a23;
|
||||
float fx, fy, fr;
|
||||
float dx, dy, dr;
|
||||
float invA, a;
|
||||
};
|
||||
|
||||
union {
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "tvgMath.h"
|
||||
#include "tvgSwCommon.h"
|
||||
|
||||
#include "tvgFill.h"
|
||||
|
||||
/************************************************************************/
|
||||
/* Internal Class Implementation */
|
||||
|
@ -32,6 +32,35 @@
|
|||
#define FIXPT_BITS 8
|
||||
#define FIXPT_SIZE (1<<FIXPT_BITS)
|
||||
|
||||
/*
|
||||
* quadratic equation with the following coefficients (rx and ry defined in the _calculateCoefficients()):
|
||||
* A = a // fill->radial.a
|
||||
* B = 2 * (dr * fr + rx * dx + ry * dy)
|
||||
* C = fr^2 - rx^2 - ry^2
|
||||
* Derivatives are computed with respect to dx.
|
||||
* This procedure aims to optimize and eliminate the need to calculate all values from the beginning
|
||||
* for consecutive x values with a constant y. The Taylor series expansions are computed as long as
|
||||
* its terms are non-zero.
|
||||
*/
|
||||
static void _calculateCoefficients(const SwFill* fill, uint32_t x, uint32_t y, float& b, float& deltaB, float& det, float& deltaDet, float& deltaDeltaDet)
|
||||
{
|
||||
auto radial = &fill->radial;
|
||||
|
||||
auto rx = (x + 0.5f) * radial->a11 + (y + 0.5f) * radial->a12 + radial->a13 - radial->fx;
|
||||
auto ry = (x + 0.5f) * radial->a21 + (y + 0.5f) * radial->a22 + radial->a23 - radial->fy;
|
||||
|
||||
b = (radial->dr * radial->fr + rx * radial->dx + ry * radial->dy) * radial->invA;
|
||||
deltaB = (radial->a11 * radial->dx + radial->a21 * radial->dy) * radial->invA;
|
||||
|
||||
auto rr = rx * rx + ry * ry;
|
||||
auto deltaRr = 2.0f * (rx * radial->a11 + ry * radial->a21) * radial->invA;
|
||||
auto deltaDeltaRr = 2.0f * (radial->a11 * radial->a11 + radial->a21 * radial->a21) * radial->invA;
|
||||
|
||||
det = b * b + (rr - radial->fr * radial->fr) * radial->invA;
|
||||
deltaDet = 2.0f * b * deltaB + deltaB * deltaB + deltaRr + deltaDeltaRr;
|
||||
deltaDeltaDet = 2.0f * deltaB * deltaB + deltaDeltaRr;
|
||||
}
|
||||
|
||||
|
||||
static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface* surface, uint8_t opacity)
|
||||
{
|
||||
|
@ -146,14 +175,36 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr
|
|||
|
||||
bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* transform)
|
||||
{
|
||||
float radius, cx, cy;
|
||||
if (radial->radial(&cx, &cy, &radius) != Result::Success) return false;
|
||||
if (radius < FLT_EPSILON) return true;
|
||||
auto cx = P(radial)->cx;
|
||||
auto cy = P(radial)->cy;
|
||||
auto r = P(radial)->r;
|
||||
auto fx = P(radial)->fx;
|
||||
auto fy = P(radial)->fy;
|
||||
auto fr = P(radial)->fr;
|
||||
|
||||
float invR = 1.0f / radius;
|
||||
fill->radial.shiftX = -cx;
|
||||
fill->radial.shiftY = -cy;
|
||||
fill->radial.a = radius;
|
||||
if (r < FLT_EPSILON) return true;
|
||||
|
||||
fill->radial.dr = r - fr;
|
||||
fill->radial.dx = cx - fx;
|
||||
fill->radial.dy = cy - fy;
|
||||
fill->radial.fr = fr;
|
||||
fill->radial.fx = fx;
|
||||
fill->radial.fy = fy;
|
||||
fill->radial.a = fill->radial.dr * fill->radial.dr - fill->radial.dx * fill->radial.dx - fill->radial.dy * fill->radial.dy;
|
||||
|
||||
//This condition fulfills the SVG 1.1 std:
|
||||
//the focal point, if outside the end circle, is moved to be on the end circle
|
||||
//See: the SVG 2 std requirements: https://www.w3.org/TR/SVG2/pservers.html#RadialGradientNotes
|
||||
if (fill->radial.a < 0) {
|
||||
auto dist = sqrtf(fill->radial.dx * fill->radial.dx + fill->radial.dy * fill->radial.dy);
|
||||
fill->radial.fx = cx + r * (fx - cx) / dist;
|
||||
fill->radial.fy = cy + r * (fy - cy) / dist;
|
||||
fill->radial.dx = cx - fill->radial.fx;
|
||||
fill->radial.dy = cy - fill->radial.fy;
|
||||
fill->radial.a = fill->radial.dr * fill->radial.dr - fill->radial.dx * fill->radial.dx - fill->radial.dy * fill->radial.dy;
|
||||
}
|
||||
|
||||
if (fill->radial.a > FLT_EPSILON) fill->radial.invA = 1.0f / fill->radial.a;
|
||||
|
||||
auto gradTransform = radial->transform();
|
||||
bool isTransformation = !mathIdentity((const Matrix*)(&gradTransform));
|
||||
|
@ -169,22 +220,17 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* tr
|
|||
Matrix invTransform;
|
||||
if (!mathInverse(&gradTransform, &invTransform)) return false;
|
||||
|
||||
fill->radial.a11 = invTransform.e11 * invR;
|
||||
fill->radial.a12 = invTransform.e12 * invR;
|
||||
fill->radial.shiftX += invTransform.e13;
|
||||
fill->radial.a21 = invTransform.e21 * invR;
|
||||
fill->radial.a22 = invTransform.e22 * invR;
|
||||
fill->radial.shiftY += invTransform.e23;
|
||||
fill->radial.detSecDeriv = 2.0f * fill->radial.a11 * fill->radial.a11 + 2 * fill->radial.a21 * fill->radial.a21;
|
||||
|
||||
fill->radial.a *= sqrt(pow(invTransform.e11, 2) + pow(invTransform.e21, 2));
|
||||
fill->radial.a11 = invTransform.e11;
|
||||
fill->radial.a12 = invTransform.e12;
|
||||
fill->radial.a13 = invTransform.e13;
|
||||
fill->radial.a21 = invTransform.e21;
|
||||
fill->radial.a22 = invTransform.e22;
|
||||
fill->radial.a23 = invTransform.e23;
|
||||
} else {
|
||||
fill->radial.a11 = fill->radial.a22 = invR;
|
||||
fill->radial.a12 = fill->radial.a21 = 0.0f;
|
||||
fill->radial.detSecDeriv = 2.0f * invR * invR;
|
||||
fill->radial.a11 = fill->radial.a22 = 1.0f;
|
||||
fill->radial.a12 = fill->radial.a13 = 0.0f;
|
||||
fill->radial.a21 = fill->radial.a23 = 0.0f;
|
||||
}
|
||||
fill->radial.shiftX *= invR;
|
||||
fill->radial.shiftY *= invR;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -235,26 +281,45 @@ static inline uint32_t _pixel(const SwFill* fill, float pos)
|
|||
|
||||
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwAlpha alpha, uint8_t csize, uint8_t opacity)
|
||||
{
|
||||
auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX;
|
||||
auto ry = (x + 0.5f) * fill->radial.a21 + (y + 0.5f) * fill->radial.a22 + fill->radial.shiftY;
|
||||
//edge case
|
||||
if (fill->radial.a < FLT_EPSILON) {
|
||||
auto radial = &fill->radial;
|
||||
auto rx = (x + 0.5f) * radial->a11 + (y + 0.5f) * radial->a12 + radial->a13 - radial->fx;
|
||||
auto ry = (x + 0.5f) * radial->a21 + (y + 0.5f) * radial->a22 + radial->a23 - radial->fy;
|
||||
|
||||
// detSecondDerivative = d(detFirstDerivative)/dx = d( d(det)/dx )/dx
|
||||
auto detSecondDerivative = fill->radial.detSecDeriv;
|
||||
// detFirstDerivative = d(det)/dx
|
||||
auto detFirstDerivative = 2.0f * (fill->radial.a11 * rx + fill->radial.a21 * ry) + 0.5f * detSecondDerivative;
|
||||
auto det = rx * rx + ry * ry;
|
||||
|
||||
if (opacity == 255) {
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) {
|
||||
*dst = opBlendNormal(_pixel(fill, sqrtf(det)), *dst, alpha(cmp));
|
||||
det += detFirstDerivative;
|
||||
detFirstDerivative += detSecondDerivative;
|
||||
if (opacity == 255) {
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) {
|
||||
auto x0 = 0.5f * (rx * rx + ry * ry - radial->fr * radial->fr) / (radial->dr * radial->fr + rx * radial->dx + ry * radial->dy);
|
||||
*dst = opBlendNormal(_pixel(fill, x0), *dst, alpha(cmp));
|
||||
rx += radial->a11;
|
||||
ry += radial->a21;
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) {
|
||||
auto x0 = 0.5f * (rx * rx + ry * ry - radial->fr * radial->fr) / (radial->dr * radial->fr + rx * radial->dx + ry * radial->dy);
|
||||
*dst = opBlendNormal(_pixel(fill, x0), *dst, MULTIPLY(opacity, alpha(cmp)));
|
||||
rx += radial->a11;
|
||||
ry += radial->a21;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) {
|
||||
*dst = opBlendNormal(_pixel(fill, sqrtf(det)), *dst, MULTIPLY(opacity, alpha(cmp)));
|
||||
det += detFirstDerivative;
|
||||
detFirstDerivative += detSecondDerivative;
|
||||
float b, deltaB, det, deltaDet, deltaDeltaDet;
|
||||
_calculateCoefficients(fill, x, y, b, deltaB, det, deltaDet, deltaDeltaDet);
|
||||
|
||||
if (opacity == 255) {
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) {
|
||||
*dst = opBlendNormal(_pixel(fill, sqrtf(det) - b), *dst, alpha(cmp));
|
||||
det += deltaDet;
|
||||
deltaDet += deltaDeltaDet;
|
||||
b += deltaB;
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) {
|
||||
*dst = opBlendNormal(_pixel(fill, sqrtf(det) - b), *dst, MULTIPLY(opacity, alpha(cmp)));
|
||||
det += deltaDet;
|
||||
deltaDet += deltaDeltaDet;
|
||||
b += deltaB;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -262,89 +327,132 @@ void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
|
|||
|
||||
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a)
|
||||
{
|
||||
auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX;
|
||||
auto ry = (x + 0.5f) * fill->radial.a21 + (y + 0.5f) * fill->radial.a22 + fill->radial.shiftY;
|
||||
if (fill->radial.a < FLT_EPSILON) {
|
||||
auto radial = &fill->radial;
|
||||
auto rx = (x + 0.5f) * radial->a11 + (y + 0.5f) * radial->a12 + radial->a13 - radial->fx;
|
||||
auto ry = (x + 0.5f) * radial->a21 + (y + 0.5f) * radial->a22 + radial->a23 - radial->fy;
|
||||
for (uint32_t i = 0; i < len; ++i, ++dst) {
|
||||
auto x0 = 0.5f * (rx * rx + ry * ry - radial->fr * radial->fr) / (radial->dr * radial->fr + rx * radial->dx + ry * radial->dy);
|
||||
*dst = op(_pixel(fill, x0), *dst, a);
|
||||
rx += radial->a11;
|
||||
ry += radial->a21;
|
||||
}
|
||||
} else {
|
||||
float b, deltaB, det, deltaDet, deltaDeltaDet;
|
||||
_calculateCoefficients(fill, x, y, b, deltaB, det, deltaDet, deltaDeltaDet);
|
||||
|
||||
// detSecondDerivative = d(detFirstDerivative)/dx = d( d(det)/dx )/dx
|
||||
auto detSecondDerivative = fill->radial.detSecDeriv;
|
||||
// detFirstDerivative = d(det)/dx
|
||||
auto detFirstDerivative = 2.0f * (fill->radial.a11 * rx + fill->radial.a21 * ry) + 0.5f * detSecondDerivative;
|
||||
auto det = rx * rx + ry * ry;
|
||||
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst) {
|
||||
*dst = op(_pixel(fill, sqrtf(det)), *dst, a);
|
||||
det += detFirstDerivative;
|
||||
detFirstDerivative += detSecondDerivative;
|
||||
for (uint32_t i = 0; i < len; ++i, ++dst) {
|
||||
*dst = op(_pixel(fill, sqrtf(det) - b), *dst, a);
|
||||
det += deltaDet;
|
||||
deltaDet += deltaDeltaDet;
|
||||
b += deltaB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fillRadial(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, SwMask maskOp, uint8_t a)
|
||||
{
|
||||
auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX;
|
||||
auto ry = (x + 0.5f) * fill->radial.a21 + (y + 0.5f) * fill->radial.a22 + fill->radial.shiftY;
|
||||
if (fill->radial.a < FLT_EPSILON) {
|
||||
auto radial = &fill->radial;
|
||||
auto rx = (x + 0.5f) * radial->a11 + (y + 0.5f) * radial->a12 + radial->a13 - radial->fx;
|
||||
auto ry = (x + 0.5f) * radial->a21 + (y + 0.5f) * radial->a22 + radial->a23 - radial->fy;
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst) {
|
||||
auto x0 = 0.5f * (rx * rx + ry * ry - radial->fr * radial->fr) / (radial->dr * radial->fr + rx * radial->dx + ry * radial->dy);
|
||||
auto src = MULTIPLY(a, A(_pixel(fill, x0)));
|
||||
*dst = maskOp(src, *dst, ~src);
|
||||
rx += radial->a11;
|
||||
ry += radial->a21;
|
||||
}
|
||||
} else {
|
||||
float b, deltaB, det, deltaDet, deltaDeltaDet;
|
||||
_calculateCoefficients(fill, x, y, b, deltaB, det, deltaDet, deltaDeltaDet);
|
||||
|
||||
// detSecondDerivative = d(detFirstDerivative)/dx = d( d(det)/dx )/dx
|
||||
auto detSecondDerivative = fill->radial.detSecDeriv;
|
||||
// detFirstDerivative = d(det)/dx
|
||||
auto detFirstDerivative = 2.0f * (fill->radial.a11 * rx + fill->radial.a21 * ry) + 0.5f * detSecondDerivative;
|
||||
auto det = rx * rx + ry * ry;
|
||||
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst) {
|
||||
auto src = MULTIPLY(a, A(_pixel(fill, sqrtf(det))));
|
||||
*dst = maskOp(src, *dst, ~src);
|
||||
det += detFirstDerivative;
|
||||
detFirstDerivative += detSecondDerivative;
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst) {
|
||||
auto src = MULTIPLY(a, A(_pixel(fill, sqrtf(det) - b)));
|
||||
*dst = maskOp(src, *dst, ~src);
|
||||
det += deltaDet;
|
||||
deltaDet += deltaDeltaDet;
|
||||
b += deltaB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fillRadial(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwMask maskOp, uint8_t a)
|
||||
{
|
||||
auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX;
|
||||
auto ry = (x + 0.5f) * fill->radial.a21 + (y + 0.5f) * fill->radial.a22 + fill->radial.shiftY;
|
||||
if (fill->radial.a < FLT_EPSILON) {
|
||||
auto radial = &fill->radial;
|
||||
auto rx = (x + 0.5f) * radial->a11 + (y + 0.5f) * radial->a12 + radial->a13 - radial->fx;
|
||||
auto ry = (x + 0.5f) * radial->a21 + (y + 0.5f) * radial->a22 + radial->a23 - radial->fy;
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst, ++cmp) {
|
||||
auto x0 = 0.5f * (rx * rx + ry * ry - radial->fr * radial->fr) / (radial->dr * radial->fr + rx * radial->dx + ry * radial->dy);
|
||||
auto src = MULTIPLY(A(A(_pixel(fill, x0))), a);
|
||||
auto tmp = maskOp(src, *cmp, 0);
|
||||
*dst = tmp + MULTIPLY(*dst, ~tmp);
|
||||
rx += radial->a11;
|
||||
ry += radial->a21;
|
||||
}
|
||||
} else {
|
||||
float b, deltaB, det, deltaDet, deltaDeltaDet;
|
||||
_calculateCoefficients(fill, x, y, b, deltaB, det, deltaDet, deltaDeltaDet);
|
||||
|
||||
// detSecondDerivative = d(detFirstDerivative)/dx = d( d(det)/dx )/dx
|
||||
auto detSecondDerivative = fill->radial.detSecDeriv;
|
||||
// detFirstDerivative = d(det)/dx
|
||||
auto detFirstDerivative = 2.0f * (fill->radial.a11 * rx + fill->radial.a21 * ry) + 0.5f * detSecondDerivative;
|
||||
auto det = rx * rx + ry * ry;
|
||||
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst, ++cmp) {
|
||||
auto src = MULTIPLY(A(_pixel(fill, sqrtf(det))), a);
|
||||
auto tmp = maskOp(src, *cmp, 0);
|
||||
*dst = tmp + MULTIPLY(*dst, ~tmp);
|
||||
det += detFirstDerivative;
|
||||
detFirstDerivative += detSecondDerivative;
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst, ++cmp) {
|
||||
auto src = MULTIPLY(A(_pixel(fill, sqrtf(det))), a);
|
||||
auto tmp = maskOp(src, *cmp, 0);
|
||||
*dst = tmp + MULTIPLY(*dst, ~tmp);
|
||||
deltaDet += deltaDeltaDet;
|
||||
b += deltaB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, SwBlender op2, uint8_t a)
|
||||
{
|
||||
auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX;
|
||||
auto ry = (x + 0.5f) * fill->radial.a21 + (y + 0.5f) * fill->radial.a22 + fill->radial.shiftY;
|
||||
if (fill->radial.a < FLT_EPSILON) {
|
||||
auto radial = &fill->radial;
|
||||
auto rx = (x + 0.5f) * radial->a11 + (y + 0.5f) * radial->a12 + radial->a13 - radial->fx;
|
||||
auto ry = (x + 0.5f) * radial->a21 + (y + 0.5f) * radial->a22 + radial->a23 - radial->fy;
|
||||
|
||||
// detSecondDerivative = d(detFirstDerivative)/dx = d( d(det)/dx )/dx
|
||||
auto detSecondDerivative = fill->radial.detSecDeriv;
|
||||
// detFirstDerivative = d(det)/dx
|
||||
auto detFirstDerivative = 2.0f * (fill->radial.a11 * rx + fill->radial.a21 * ry) + 0.5f * detSecondDerivative;
|
||||
auto det = rx * rx + ry * ry;
|
||||
|
||||
if (a == 255) {
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst) {
|
||||
auto tmp = op(_pixel(fill, sqrtf(det)), *dst, 255);
|
||||
*dst = op2(tmp, *dst, 255);
|
||||
det += detFirstDerivative;
|
||||
detFirstDerivative += detSecondDerivative;
|
||||
if (a == 255) {
|
||||
for (uint32_t i = 0; i < len; ++i, ++dst) {
|
||||
auto x0 = 0.5f * (rx * rx + ry * ry - radial->fr * radial->fr) / (radial->dr * radial->fr + rx * radial->dx + ry * radial->dy);
|
||||
auto tmp = op(_pixel(fill, x0), *dst, 255);
|
||||
*dst = op2(tmp, *dst, 255);
|
||||
rx += radial->a11;
|
||||
ry += radial->a21;
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0; i < len; ++i, ++dst) {
|
||||
auto x0 = 0.5f * (rx * rx + ry * ry - radial->fr * radial->fr) / (radial->dr * radial->fr + rx * radial->dx + ry * radial->dy);
|
||||
auto tmp = op(_pixel(fill, x0), *dst, 255);
|
||||
auto tmp2 = op2(tmp, *dst, 255);
|
||||
*dst = INTERPOLATE(tmp2, *dst, a);
|
||||
rx += radial->a11;
|
||||
ry += radial->a21;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst) {
|
||||
auto tmp = op(_pixel(fill, sqrtf(det)), *dst, 255);
|
||||
auto tmp2 = op2(tmp, *dst, 255);
|
||||
*dst = INTERPOLATE(tmp2, *dst, a);
|
||||
det += detFirstDerivative;
|
||||
detFirstDerivative += detSecondDerivative;
|
||||
float b, deltaB, det, deltaDet, deltaDeltaDet;
|
||||
_calculateCoefficients(fill, x, y, b, deltaB, det, deltaDet, deltaDeltaDet);
|
||||
if (a == 255) {
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst) {
|
||||
auto tmp = op(_pixel(fill, sqrtf(det) - b), *dst, 255);
|
||||
*dst = op2(tmp, *dst, 255);
|
||||
det += deltaDet;
|
||||
deltaDet += deltaDeltaDet;
|
||||
b += deltaB;
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst) {
|
||||
auto tmp = op(_pixel(fill, sqrtf(det) - b), *dst, 255);
|
||||
auto tmp2 = op2(tmp, *dst, 255);
|
||||
*dst = INTERPOLATE(tmp2, *dst, a);
|
||||
det += deltaDet;
|
||||
deltaDet += deltaDeltaDet;
|
||||
b += deltaB;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1595,8 +1595,6 @@ static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region,
|
|||
|
||||
static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
|
||||
{
|
||||
if (fill->radial.a < FLT_EPSILON) return false;
|
||||
|
||||
if (_compositing(surface)) {
|
||||
if (_matting(surface)) return _rasterGradientMattedRect<FillRadial>(surface, region, fill);
|
||||
else return _rasterGradientMaskedRect<FillRadial>(surface, region, fill);
|
||||
|
@ -1610,7 +1608,6 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region,
|
|||
}
|
||||
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Rle Gradient */
|
||||
/************************************************************************/
|
||||
|
@ -1741,7 +1738,7 @@ static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, c
|
|||
|
||||
static bool _rasterRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
|
||||
{
|
||||
if (!rle || fill->radial.a < FLT_EPSILON) return false;
|
||||
if (!rle) return false;
|
||||
|
||||
if (_compositing(surface)) {
|
||||
if (_matting(surface)) return _rasterGradientMattedRle<FillRadial>(surface, rle, fill);
|
||||
|
|
|
@ -26,6 +26,50 @@
|
|||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
Fill* RadialGradient::Impl::duplicate()
|
||||
{
|
||||
auto ret = RadialGradient::gen();
|
||||
if (!ret) return nullptr;
|
||||
|
||||
ret->pImpl->cx = cx;
|
||||
ret->pImpl->cy = cy;
|
||||
ret->pImpl->r = r;
|
||||
ret->pImpl->fx = fx;
|
||||
ret->pImpl->fy = fy;
|
||||
ret->pImpl->fr = fr;
|
||||
|
||||
return ret.release();
|
||||
}
|
||||
|
||||
|
||||
Result RadialGradient::Impl::radial(float cx, float cy, float r, float fx, float fy, float fr)
|
||||
{
|
||||
if (r < 0 || fr < 0) return Result::InvalidArguments;
|
||||
|
||||
this->cx = cx;
|
||||
this->cy = cy;
|
||||
this->r = r;
|
||||
this->fx = fx;
|
||||
this->fy = fy;
|
||||
this->fr = fr;
|
||||
|
||||
return Result::Success;
|
||||
};
|
||||
|
||||
|
||||
Fill* LinearGradient::Impl::duplicate()
|
||||
{
|
||||
auto ret = LinearGradient::gen();
|
||||
if (!ret) return nullptr;
|
||||
|
||||
ret->pImpl->x1 = x1;
|
||||
ret->pImpl->y1 = y1;
|
||||
ret->pImpl->x2 = x2;
|
||||
ret->pImpl->y2 = y2;
|
||||
|
||||
return ret.release();
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
|
@ -110,7 +154,97 @@ Fill* Fill::duplicate() const noexcept
|
|||
return pImpl->duplicate();
|
||||
}
|
||||
|
||||
|
||||
uint32_t Fill::identifier() const noexcept
|
||||
{
|
||||
return pImpl->id;
|
||||
}
|
||||
|
||||
|
||||
RadialGradient::RadialGradient():pImpl(new Impl())
|
||||
{
|
||||
Fill::pImpl->id = TVG_CLASS_ID_RADIAL;
|
||||
Fill::pImpl->method(new FillDup<RadialGradient::Impl>(pImpl));
|
||||
}
|
||||
|
||||
|
||||
RadialGradient::~RadialGradient()
|
||||
{
|
||||
delete(pImpl);
|
||||
}
|
||||
|
||||
|
||||
Result RadialGradient::radial(float cx, float cy, float r) noexcept
|
||||
{
|
||||
return pImpl->radial(cx, cy, r, cx, cy, 0.0f);
|
||||
}
|
||||
|
||||
|
||||
Result RadialGradient::radial(float* cx, float* cy, float* r) const noexcept
|
||||
{
|
||||
if (cx) *cx = pImpl->cx;
|
||||
if (cy) *cy = pImpl->cy;
|
||||
if (r) *r = pImpl->r;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
unique_ptr<RadialGradient> RadialGradient::gen() noexcept
|
||||
{
|
||||
return unique_ptr<RadialGradient>(new RadialGradient);
|
||||
}
|
||||
|
||||
|
||||
uint32_t RadialGradient::identifier() noexcept
|
||||
{
|
||||
return TVG_CLASS_ID_RADIAL;
|
||||
}
|
||||
|
||||
|
||||
LinearGradient::LinearGradient():pImpl(new Impl())
|
||||
{
|
||||
Fill::pImpl->id = TVG_CLASS_ID_LINEAR;
|
||||
Fill::pImpl->method(new FillDup<LinearGradient::Impl>(pImpl));
|
||||
}
|
||||
|
||||
|
||||
LinearGradient::~LinearGradient()
|
||||
{
|
||||
delete(pImpl);
|
||||
}
|
||||
|
||||
|
||||
Result LinearGradient::linear(float x1, float y1, float x2, float y2) noexcept
|
||||
{
|
||||
pImpl->x1 = x1;
|
||||
pImpl->y1 = y1;
|
||||
pImpl->x2 = x2;
|
||||
pImpl->y2 = y2;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
Result LinearGradient::linear(float* x1, float* y1, float* x2, float* y2) const noexcept
|
||||
{
|
||||
if (x1) *x1 = pImpl->x1;
|
||||
if (x2) *x2 = pImpl->x2;
|
||||
if (y1) *y1 = pImpl->y1;
|
||||
if (y2) *y2 = pImpl->y2;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
unique_ptr<LinearGradient> LinearGradient::gen() noexcept
|
||||
{
|
||||
return unique_ptr<LinearGradient>(new LinearGradient);
|
||||
}
|
||||
|
||||
|
||||
uint32_t LinearGradient::identifier() noexcept
|
||||
{
|
||||
return TVG_CLASS_ID_LINEAR;
|
||||
}
|
||||
|
||||
|
|
|
@ -86,4 +86,27 @@ struct Fill::Impl
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
struct RadialGradient::Impl
|
||||
{
|
||||
float cx = 0.0f, cy = 0.0f;
|
||||
float fx = 0.0f, fy = 0.0f;
|
||||
float r = 0.0f, fr = 0.0f;
|
||||
|
||||
Fill* duplicate();
|
||||
Result radial(float cx, float cy, float r, float fx, float fy, float fr);
|
||||
};
|
||||
|
||||
|
||||
struct LinearGradient::Impl
|
||||
{
|
||||
float x1 = 0.0f;
|
||||
float y1 = 0.0f;
|
||||
float x2 = 0.0f;
|
||||
float y2 = 0.0f;
|
||||
|
||||
Fill* duplicate();
|
||||
};
|
||||
|
||||
|
||||
#endif //_TVG_FILL_H_
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include "tvgFill.h"
|
||||
|
||||
/************************************************************************/
|
||||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
struct LinearGradient::Impl
|
||||
{
|
||||
float x1 = 0;
|
||||
float y1 = 0;
|
||||
float x2 = 0;
|
||||
float y2 = 0;
|
||||
|
||||
Fill* duplicate()
|
||||
{
|
||||
auto ret = LinearGradient::gen();
|
||||
if (!ret) return nullptr;
|
||||
|
||||
ret->pImpl->x1 = x1;
|
||||
ret->pImpl->y1 = y1;
|
||||
ret->pImpl->x2 = x2;
|
||||
ret->pImpl->y2 = y2;
|
||||
|
||||
return ret.release();
|
||||
}
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
LinearGradient::LinearGradient():pImpl(new Impl())
|
||||
{
|
||||
Fill::pImpl->id = TVG_CLASS_ID_LINEAR;
|
||||
Fill::pImpl->method(new FillDup<LinearGradient::Impl>(pImpl));
|
||||
}
|
||||
|
||||
|
||||
LinearGradient::~LinearGradient()
|
||||
{
|
||||
delete(pImpl);
|
||||
}
|
||||
|
||||
|
||||
Result LinearGradient::linear(float x1, float y1, float x2, float y2) noexcept
|
||||
{
|
||||
pImpl->x1 = x1;
|
||||
pImpl->y1 = y1;
|
||||
pImpl->x2 = x2;
|
||||
pImpl->y2 = y2;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
Result LinearGradient::linear(float* x1, float* y1, float* x2, float* y2) const noexcept
|
||||
{
|
||||
if (x1) *x1 = pImpl->x1;
|
||||
if (x2) *x2 = pImpl->x2;
|
||||
if (y1) *y1 = pImpl->y1;
|
||||
if (y2) *y2 = pImpl->y2;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
unique_ptr<LinearGradient> LinearGradient::gen() noexcept
|
||||
{
|
||||
return unique_ptr<LinearGradient>(new LinearGradient);
|
||||
}
|
||||
|
||||
|
||||
uint32_t LinearGradient::identifier() noexcept
|
||||
{
|
||||
return TVG_CLASS_ID_LINEAR;
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <float.h>
|
||||
#include "tvgFill.h"
|
||||
|
||||
/************************************************************************/
|
||||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
struct RadialGradient::Impl
|
||||
{
|
||||
float cx = 0;
|
||||
float cy = 0;
|
||||
float radius = 0;
|
||||
|
||||
Fill* duplicate()
|
||||
{
|
||||
auto ret = RadialGradient::gen();
|
||||
if (!ret) return nullptr;
|
||||
|
||||
ret->pImpl->cx = cx;
|
||||
ret->pImpl->cy = cy;
|
||||
ret->pImpl->radius = radius;
|
||||
|
||||
return ret.release();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
RadialGradient::RadialGradient():pImpl(new Impl())
|
||||
{
|
||||
Fill::pImpl->id = TVG_CLASS_ID_RADIAL;
|
||||
Fill::pImpl->method(new FillDup<RadialGradient::Impl>(pImpl));
|
||||
}
|
||||
|
||||
|
||||
RadialGradient::~RadialGradient()
|
||||
{
|
||||
delete(pImpl);
|
||||
}
|
||||
|
||||
|
||||
Result RadialGradient::radial(float cx, float cy, float radius) noexcept
|
||||
{
|
||||
if (radius < 0) return Result::InvalidArguments;
|
||||
|
||||
pImpl->cx = cx;
|
||||
pImpl->cy = cy;
|
||||
pImpl->radius = radius;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
Result RadialGradient::radial(float* cx, float* cy, float* radius) const noexcept
|
||||
{
|
||||
if (cx) *cx = pImpl->cx;
|
||||
if (cy) *cy = pImpl->cy;
|
||||
if (radius) *radius = pImpl->radius;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
unique_ptr<RadialGradient> RadialGradient::gen() noexcept
|
||||
{
|
||||
return unique_ptr<RadialGradient>(new RadialGradient);
|
||||
}
|
||||
|
||||
|
||||
uint32_t RadialGradient::identifier() noexcept
|
||||
{
|
||||
return TVG_CLASS_ID_RADIAL;
|
||||
}
|
Loading…
Add table
Reference in a new issue