ultimatepp/uppsrc/Painter/RadialGradient.cpp
cxl fc28952132 Painter: Now caching gradients
git-svn-id: svn://ultimatepp.org/upp/trunk@12537 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2018-11-14 14:46:15 +00:00

97 lines
2.8 KiB
C++

#include "Painter.h"
namespace Upp {
struct PainterRadialSpan : SpanSource {
LinearInterpolator interpolator;
double cx, cy, r, fx, fy;
int style;
int alpha;
const RGBA *gradient;
double C;
void Set(double _x, double _y, double _r, double _fx, double _fy)
{
cx = _x;
cy = _y;
r = _r;
fx = _fx;
fy = _fy;
fx -= cx;
fy -= cy;
C = fx * fx + fy * fy - r * r;
}
void Get(RGBA *_span, int x, int y, unsigned len)
{
if(r <= 0)
return;
interpolator.Begin(x, y, len);
RGBA *span = (RGBA *)_span;
while(len--) {
Point p = interpolator.Get();
int h;
const double q256 = 1 / 256.0;
double dx = q256 * p.x - cx - fx;
double dy = q256 * p.y - cy - fy;
if(dx == 0 && dy == 0)
h = 0;
else {
double A = dx * dx + dy * dy;
double b = (fx * dx + fy * dy);
double t = (sqrt(b * b - A * C) - b) / (A);
h = t >= 0.001 ? int(2047 / t) : 2047;
}
if(style == GRADIENT_REPEAT)
h = h & 2047;
else
if(style == GRADIENT_REFLECT)
h = (h & 2048) ? (2047 - h & 2047) : (h & 2047);
else
h = minmax(h, 0, 2047);
*span++ = gradient[h];
}
}
};
void BufferPainter::RenderRadial(double width, const Pointf& f, const RGBA& color1,
const Pointf& c, double r, const RGBA& color2,
const Xform2D& m, int style)
{
Image gradient = Gradient(color1, color2, 2048);
RenderPath(width, [=](One<SpanSource>& ss) {
PainterRadialSpan& sg = ss.Create<PainterRadialSpan>();
sg.interpolator.Set(Inverse(m));
sg.style = style;
sg.Set(c.x, c.y, r, f.x, f.y);
sg.gradient = gradient[0];
}, RGBAZero());
}
void BufferPainter::FillOp(const Pointf& f, const RGBA& color1, const Pointf& c, double r, const RGBA& color2, int style)
{
RenderRadial(-1, f, color1, c, r, color2, pathattr.mtx, style);
}
void BufferPainter::StrokeOp(double width, const Pointf& f, const RGBA& color1, const Pointf& c, double r, const RGBA& color2, int style)
{
RenderRadial(width, f, color1, c, r, color2, pathattr.mtx, style);
}
void BufferPainter::RenderRadial(double width, const Pointf& f, const RGBA& color1,
const RGBA& color2, const Xform2D& transsrc, int style)
{
RenderRadial(width, f, color1, Pointf(0, 0), 1, color2, transsrc * pathattr.mtx, style);
}
void BufferPainter::FillOp(const Pointf& f, const RGBA& color1, const RGBA& color2, const Xform2D& transsrc, int style)
{
RenderRadial(-1, f, color1, color2, transsrc, style);
}
void BufferPainter::StrokeOp(double width, const Pointf& f, const RGBA& color1, const RGBA& color2, const Xform2D& transsrc, int style)
{
RenderRadial(width, f, color1, color2, transsrc, style);
}
}