Subpixel rendering support in Painter

git-svn-id: svn://ultimatepp.org/upp/trunk@883 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2009-02-21 19:03:39 +00:00
parent d712944aaa
commit 7db4871131
13 changed files with 1574 additions and 1496 deletions

View file

@ -1,89 +1,72 @@
#include "Painter.h"
NAMESPACE_UPP
static void sQuadratic(LinearPathConsumer& t, const Pointf& p1, const Pointf& p2, const Pointf& p3,
double qt, int lvl)
{
if(lvl < 16) {
Pointf d = p3 - p1;
double q = Squared(d);
if(q > 1e-30) {
Pointf pd = p2 - p1;
double u = (pd.x * d.x + pd.y * d.y) / q;
if(u <= 0 || u >= 1 || SquaredDistance(u * d, pd) > qt) {
Pointf p12 = Mid(p1, p2);
Pointf p23 = Mid(p2, p3);
Pointf div = Mid(p12, p23);
sQuadratic(t, p1, p12, div, qt, lvl + 1);
sQuadratic(t, div, p23, p3, qt, lvl + 1);
return;
}
}
}
t.Line(p3);
}
void ApproximateQuadratic(LinearPathConsumer& t, const Pointf& p1, const Pointf& p2, const Pointf& p3,
double tolerance)
{
sQuadratic(t, p1, p2, p3, tolerance * tolerance, 0);
t.Line(p3);
}
static void sCubic(LinearPathConsumer& t,
const Pointf& p1, const Pointf& p2, const Pointf& p3, const Pointf& p4,
double qt, int lvl)
{
if(lvl < 16) {
Pointf d = p4 - p1;
double q = d.x * d.x + d.y * d.y;
if(q >= 1e-30) {
Pointf d2 = p2 - p1;
Pointf d3 = p3 - p1;
double u1 = (d2.x * d.x + d2.y * d.y) / q;
double u2 = (d3.x * d.x + d3.y * d.y) / q;
if(u1 <= 0 || u1 >= 1 || u2 <= 0 || u2 >= 1 ||
SquaredDistance(u1 * d, d2) > qt || SquaredDistance(u2 * d, d3) > qt) {
Pointf p12 = Mid(p1, p2);
Pointf p23 = Mid(p2, p3);
Pointf p34 = Mid(p3, p4);
Pointf p123 = Mid(p12, p23);
Pointf p234 = Mid(p23, p34);
Pointf div = Mid(p123, p234);
Pointf p14 = Mid(p1, p4);
sCubic(t, p1, p12, p123, div, qt, lvl + 1);
sCubic(t, div, p234, p34, p4, qt, lvl + 1);
return;
}
}
}
t.Line(p4);
}
void ApproximateCubic(LinearPathConsumer& t,
const Pointf& p1, const Pointf& p2, const Pointf& p3, const Pointf& p4,
double tolerance)
{
sCubic(t, p1, p2, p3, p4, tolerance * tolerance, 0);
t.Line(p4);
}
void ApproximateArc(LinearPathConsumer& t, const Pointf& c, const Pointf& r,
double angle, double sweep, double tolerance)
{
while(angle + sweep < 0)
angle += 2000 * M_PI;
double fid = acos(1 - tolerance / max(r.x, r.y));
if(fabs(sweep / fid) > 1000)
fid = sweep / 1000;
double a = angle;
double e = angle + sweep;
while(fid > 0 ? a < e : a > e) {
t.Line(Polar(a) * r + c);
a += fid;
}
t.Line(Polar(angle + sweep) * r + c);
}
END_UPP_NAMESPACE
#include "Painter.h"
NAMESPACE_UPP
static void sQuadratic(LinearPathConsumer& t, const Pointf& p1, const Pointf& p2, const Pointf& p3,
double qt, int lvl)
{
if(lvl < 16) {
Pointf d = p3 - p1;
double q = Squared(d);
if(q > 1e-30) {
Pointf pd = p2 - p1;
double u = (pd.x * d.x + pd.y * d.y) / q;
if(u <= 0 || u >= 1 || SquaredDistance(u * d, pd) > qt) {
Pointf p12 = Mid(p1, p2);
Pointf p23 = Mid(p2, p3);
Pointf div = Mid(p12, p23);
sQuadratic(t, p1, p12, div, qt, lvl + 1);
sQuadratic(t, div, p23, p3, qt, lvl + 1);
return;
}
}
}
t.Line(p3);
}
void ApproximateQuadratic(LinearPathConsumer& t, const Pointf& p1, const Pointf& p2, const Pointf& p3,
double tolerance)
{
sQuadratic(t, p1, p2, p3, tolerance * tolerance, 0);
t.Line(p3);
}
static void sCubic(LinearPathConsumer& t,
const Pointf& p1, const Pointf& p2, const Pointf& p3, const Pointf& p4,
double qt, int lvl)
{
if(lvl < 16) {
Pointf d = p4 - p1;
double q = d.x * d.x + d.y * d.y;
if(q >= 1e-30) {
Pointf d2 = p2 - p1;
Pointf d3 = p3 - p1;
double u1 = (d2.x * d.x + d2.y * d.y) / q;
double u2 = (d3.x * d.x + d3.y * d.y) / q;
if(u1 <= 0 || u1 >= 1 || u2 <= 0 || u2 >= 1 ||
SquaredDistance(u1 * d, d2) > qt || SquaredDistance(u2 * d, d3) > qt) {
Pointf p12 = Mid(p1, p2);
Pointf p23 = Mid(p2, p3);
Pointf p34 = Mid(p3, p4);
Pointf p123 = Mid(p12, p23);
Pointf p234 = Mid(p23, p34);
Pointf div = Mid(p123, p234);
Pointf p14 = Mid(p1, p4);
sCubic(t, p1, p12, p123, div, qt, lvl + 1);
sCubic(t, div, p234, p34, p4, qt, lvl + 1);
return;
}
}
}
t.Line(p4);
}
void ApproximateCubic(LinearPathConsumer& t,
const Pointf& p1, const Pointf& p2, const Pointf& p3, const Pointf& p4,
double tolerance)
{
sCubic(t, p1, p2, p3, p4, tolerance * tolerance, 0);
t.Line(p4);
}
END_UPP_NAMESPACE

View file

@ -1,352 +1,347 @@
Pointf Mid(const Pointf& a, const Pointf& b);
Pointf Orthogonal(const Pointf& p);
double Squared(const Pointf& p);
double Length(const Pointf& p);
double Bearing(const Pointf& p);
double Distance(const Pointf& p1, const Pointf& p2);
double SquaredDistance(const Pointf& p1, const Pointf& p2);
Pointf Polar(double a);
Pointf Polar(const Pointf& p, double r, double a);
struct LinearPathConsumer {
virtual void Move(const Pointf& p) = 0;
virtual void Line(const Pointf& p) = 0;
virtual void End();
};
void ApproximateQuadratic(LinearPathConsumer& t,
const Pointf& p1, const Pointf& p2, const Pointf& p3,
double tolerance);
void ApproximateCubic(LinearPathConsumer& t,
const Pointf& x0, const Pointf& x1, const Pointf& x2, const Pointf& x,
double tolerance);
void ApproximateArc(LinearPathConsumer& t, const Pointf& p, const Pointf& r,
double angle, double sweep, double tolerance);
struct LinearPathFilter : LinearPathConsumer {
virtual void End();
LinearPathConsumer *target;
void PutMove(const Pointf& p) { target->Move(p); }
void PutLine(const Pointf& p) { target->Line(p); }
void PutEnd() { target->End(); }
};
class Stroker : public LinearPathFilter {
public:
virtual void Move(const Pointf& p);
virtual void Line(const Pointf& p);
virtual void End();
private:
double w2;
double qmiter;
double fid;
Pointf p0, v0, o0, a0, b0;
Pointf p1, v1, o1, a1, b1;
Pointf p2;
int linecap;
int linejoin;
void Finish();
void Round(const Pointf& p, const Pointf& v1, const Pointf& v2, double r);
void Cap(const Pointf& p0, const Pointf& v0, const Pointf& o0,
const Pointf& a0, const Pointf& b0);
public:
void Init(double width, double miterlimit, double tolerance, int linecap, int linejoin);
};
class Dasher : public LinearPathFilter {
public:
virtual void Move(const Pointf& p);
virtual void Line(const Pointf& p);
private:
const Vector<double> *pattern;
int patterni;
double sum, rem;
bool flag;
Pointf p0;
void Put(const Pointf& p);
public:
void Init(const Vector<double>& pattern, double distance);
};
struct Transformer : public LinearPathFilter {
public:
virtual void Move(const Pointf& p);
virtual void Line(const Pointf& p);
private:
const Xform2D& xform;
public:
Transformer(const Xform2D& xform) : xform(xform) {}
};
inline RGBA Mul8(const RGBA& s, int mul)
{
RGBA t;
t.r = (mul * s.r) >> 8;
t.g = (mul * s.g) >> 8;
t.b = (mul * s.b) >> 8;
t.a = (mul * s.a) >> 8;
return t;
}
inline void AlphaBlend(RGBA& t, const RGBA& c)
{
int alpha = 256 - (c.a + (c.a >> 7));
t.r = c.r + (alpha * t.r >> 8);
t.g = c.g + (alpha * t.g >> 8);
t.b = c.b + (alpha * t.b >> 8);
t.a = c.a + (alpha * t.a >> 8);
}
inline void AlphaBlendCover8(RGBA& t, const RGBA& c, int cover)
{
int a = c.a * cover >> 8;
int alpha = 256 - (a + (a >> 7));
t.r = (c.r * cover >> 8) + (alpha * t.r >> 8);
t.g = (c.g * cover >> 8) + (alpha * t.g >> 8);
t.b = (c.b * cover >> 8) + (alpha * t.b >> 8);
t.a = a + (alpha * t.a >> 8);
}
inline int Q8(double x)
{
return int(x * 256 + 0.5);
}
class Rasterizer : public LinearPathConsumer {
public:
virtual void Move(const Pointf& p);
virtual void Line(const Pointf& p);
private:
struct Cell : Moveable<Cell> {
int16 x;
int16 cover;
int area;
bool operator<(const Cell& b) const { return x < b.x; }
};
Rectf cliprect;
Pointf p0;
Buffer< Vector<Cell> > cell;
int min_y;
int max_y;
Size sz;
void Init();
Cell *AddCells(int y, int n);
void RenderHLine(int ey, int x1, int y1, int x2, int y2);
void LineClip(double x1, double y1, double x2, double y2);
int CvX(double x);
int CvY(double y);
void CvLine(double x1, double y1, double x2, double y2);
bool BeginRender(int y, const Cell *&c, const Cell *&e);
public:
struct Filler {
virtual void Start(int x, int len) = 0;
virtual void Render(int val) = 0;
virtual void Render(int val, int len) = 0;
};
void LineRaw(int x1, int y1, int x2, int y2);
void SetClip(const Rectf& rect);
int MinY() const { return min_y; }
int MaxY() const { return max_y; }
void Render(int y, Filler& g, bool evenodd);
void Reset();
Rasterizer(int cx, int cy);
};
struct SpanSource {
virtual void Get(RGBA *span, int x, int y, unsigned len) = 0;
};
class ClipLine : NoCopy {
byte *data;
public:
void Clear() { if(!IsFull()) delete[] data; data = NULL; }
void Set(const byte *s, int len) { data = new byte[len]; memcpy(data, s, len); }
void SetFull() { ASSERT(!data); data = (byte *)1; }
bool IsEmpty() const { return !data; }
bool IsFull() const { return data == (byte *)1; }
operator const byte*() const { return data; }
ClipLine() { data = NULL; }
~ClipLine() { Clear(); }
};
Image MipMap(const Image& img);
Image MakeMipMap(const Image& img, int level);
class LinearInterpolator {
struct Dda2 {
int count, lift, rem, mod, p;
void Set(int a, int b, int len);
int Get();
};
Xform2D xform;
Dda2 ddax, dday;
public:
void Set(const Xform2D& m) { xform = m; }
void Begin(int x, int y, int len);
Point Get();
};
class BufferPainter : public Painter {
protected:
virtual void ClearOp(const RGBA& color);
virtual void MoveOp(const Pointf& p, bool rel);
virtual void LineOp(const Pointf& p, bool rel);
virtual void QuadraticOp(const Pointf& p1, const Pointf& p, bool rel);
virtual void QuadraticOp(const Pointf& p, bool rel);
virtual void CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel);
virtual void CubicOp(const Pointf& p2, const Pointf& p, bool rel);
virtual void ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel);
virtual void SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep,
const Pointf& p, bool rel);
virtual void CloseOp();
virtual void DivOp();
virtual void FillOp(const RGBA& color);
virtual void FillOp(const Image& image, const Xform2D& transsrc, dword flags);
virtual void FillOp(const Pointf& p1, const RGBA& color1,
const Pointf& p2, const RGBA& color2,
int style);
virtual void FillOp(const Pointf& f, const RGBA& color1,
const Pointf& c, double r, const RGBA& color2,
int style);
virtual void StrokeOp(double width, const RGBA& rgba);
virtual void StrokeOp(double width, const Image& image, const Xform2D& transsrc,
dword flags);
virtual void StrokeOp(double width, const Pointf& p1, const RGBA& color1,
const Pointf& p2, const RGBA& color2,
int style);
virtual void StrokeOp(double width, const Pointf& f, const RGBA& color1,
const Pointf& c, double r, const RGBA& color2,
int style);
virtual void ClipOp();
virtual void ColorStopOp(double pos, const RGBA& color);
virtual void ClearStopsOp();
virtual void OpacityOp(double o);
virtual void LineCapOp(int linecap);
virtual void LineJoinOp(int linejoin);
virtual void MiterLimitOp(double l);
virtual void EvenOddOp(bool evenodd);
virtual void DashOp(const Vector<double>& dash, double start);
virtual void NoAAOp(bool noaa);
virtual void TransformOp(const Xform2D& m);
virtual void BeginOp();
virtual void EndOp();
virtual void BeginMaskOp();
public:
enum {
MOVE, LINE, QUADRATIC, CUBIC, ARC, DIV
};
struct LinearData {
Pointf p;
};
struct QuadraticData : LinearData {
Pointf p1;
};
struct CubicData : QuadraticData {
Pointf p2;
};
struct ArcData : LinearData {
Pointf r;
double angle, sweep;
Pointf EndPoint() const;
};
struct Path {
Vector<byte> type;
Vector<byte> data;
};
struct Attr : Moveable<Attr> {
Xform2D mtx;
double tolerance;
bool evenodd;
byte join;
byte cap;
double miter_limit;
WithDeepCopy< Vector<double> > dash;
WithDeepCopy< Vector<double> > stop;
WithDeepCopy< Vector<RGBA> > stop_color;
double dash_start;
double opacity;
int cliplevel;
bool hasclip;
bool mask;
bool noaa;
};
ImageBuffer& ib;
Attr attr;
Attr pathattr;
Array<Attr> attrstack;
Vector< Buffer<ClipLine> > clip;
Array< ImageBuffer > mask;
Image gradient;
RGBA gradient1, gradient2;
int gradientn;
Path path;
Pointf current, ccontrol, qcontrol, move;
Rectf pathrect;
Rasterizer rasterizer;
Buffer<RGBA> span;
void *PathAddRaw(int type, int size);
template <class T> T& PathAdd(int type) { return *(T *)PathAddRaw(type, sizeof(T)); }
Pointf PathPoint(const Pointf& p, bool rel);
Pointf EndPoint(const Pointf& p, bool rel);
void DoMove0();
void ClearPath();
Buffer<ClipLine> RenderPath(double width, SpanSource *ss, const RGBA& color);
void RenderImage(double width, const Image& image, const Xform2D& transsrc,
dword flags);
void RenderRadial(double width, const Pointf& f, const RGBA& color1,
const Pointf& c, double r, const RGBA& color2, int style);
void MakeGradient(RGBA color1, RGBA color2, int cx);
void Gradient(const RGBA& color1, const RGBA& color2, const Pointf& p1, const Pointf& p2);
void ColorStop0(Attr& a, double pos, const RGBA& color);
void FinishMask();
public:
BufferPainter(ImageBuffer& ib);
};
Pointf Mid(const Pointf& a, const Pointf& b);
Pointf Orthogonal(const Pointf& p);
double Squared(const Pointf& p);
double Length(const Pointf& p);
double Bearing(const Pointf& p);
double Distance(const Pointf& p1, const Pointf& p2);
double SquaredDistance(const Pointf& p1, const Pointf& p2);
Pointf Polar(double a);
Pointf Polar(const Pointf& p, double r, double a);
struct LinearPathConsumer {
virtual void Move(const Pointf& p) = 0;
virtual void Line(const Pointf& p) = 0;
virtual void End();
};
void ApproximateQuadratic(LinearPathConsumer& t,
const Pointf& p1, const Pointf& p2, const Pointf& p3,
double tolerance);
void ApproximateCubic(LinearPathConsumer& t,
const Pointf& x0, const Pointf& x1, const Pointf& x2, const Pointf& x,
double tolerance);
struct LinearPathFilter : LinearPathConsumer {
virtual void End();
LinearPathConsumer *target;
void PutMove(const Pointf& p) { target->Move(p); }
void PutLine(const Pointf& p) { target->Line(p); }
void PutEnd() { target->End(); }
};
class Stroker : public LinearPathFilter {
public:
virtual void Move(const Pointf& p);
virtual void Line(const Pointf& p);
virtual void End();
private:
double w2;
double qmiter;
double fid;
Pointf p0, v0, o0, a0, b0;
Pointf p1, v1, o1, a1, b1;
Pointf p2;
int linecap;
int linejoin;
void Finish();
void Round(const Pointf& p, const Pointf& v1, const Pointf& v2, double r);
void Cap(const Pointf& p0, const Pointf& v0, const Pointf& o0,
const Pointf& a0, const Pointf& b0);
public:
void Init(double width, double miterlimit, double tolerance, int linecap, int linejoin);
};
class Dasher : public LinearPathFilter {
public:
virtual void Move(const Pointf& p);
virtual void Line(const Pointf& p);
private:
const Vector<double> *pattern;
int patterni;
double sum, rem;
bool flag;
Pointf p0;
void Put(const Pointf& p);
public:
void Init(const Vector<double>& pattern, double distance);
};
struct Transformer : public LinearPathFilter {
public:
virtual void Move(const Pointf& p);
virtual void Line(const Pointf& p);
private:
const Xform2D& xform;
public:
Transformer(const Xform2D& xform) : xform(xform) {}
};
inline RGBA Mul8(const RGBA& s, int mul)
{
RGBA t;
t.r = (mul * s.r) >> 8;
t.g = (mul * s.g) >> 8;
t.b = (mul * s.b) >> 8;
t.a = (mul * s.a) >> 8;
return t;
}
inline void AlphaBlend(RGBA& t, const RGBA& c)
{
int alpha = 256 - (c.a + (c.a >> 7));
t.r = c.r + (alpha * t.r >> 8);
t.g = c.g + (alpha * t.g >> 8);
t.b = c.b + (alpha * t.b >> 8);
t.a = c.a + (alpha * t.a >> 8);
}
inline void AlphaBlendCover8(RGBA& t, const RGBA& c, int cover)
{
int a = c.a * cover >> 8;
int alpha = 256 - (a + (a >> 7));
t.r = (c.r * cover >> 8) + (alpha * t.r >> 8);
t.g = (c.g * cover >> 8) + (alpha * t.g >> 8);
t.b = (c.b * cover >> 8) + (alpha * t.b >> 8);
t.a = a + (alpha * t.a >> 8);
}
inline int Q8(double x)
{
return int(x * 256 + 0.5);
}
class Rasterizer : public LinearPathConsumer {
public:
virtual void Move(const Pointf& p);
virtual void Line(const Pointf& p);
private:
struct Cell : Moveable<Cell> {
int16 x;
int16 cover;
int area;
bool operator<(const Cell& b) const { return x < b.x; }
};
Rectf cliprect;
Pointf p0;
Buffer< Vector<Cell> > cell;
int min_y;
int max_y;
Size sz;
void Init();
Cell *AddCells(int y, int n);
void RenderHLine(int ey, int x1, int y1, int x2, int y2);
void LineClip(double x1, double y1, double x2, double y2);
int CvX(double x);
int CvY(double y);
void CvLine(double x1, double y1, double x2, double y2);
bool BeginRender(int y, const Cell *&c, const Cell *&e);
public:
struct Filler {
virtual void Start(int x, int len) = 0;
virtual void Render(int val) = 0;
virtual void Render(int val, int len) = 0;
virtual void End();
};
void LineRaw(int x1, int y1, int x2, int y2);
void SetClip(const Rectf& rect);
int MinY() const { return min_y; }
int MaxY() const { return max_y; }
void Render(int y, Filler& g, bool evenodd);
void Reset();
Rasterizer(int cx, int cy);
};
struct SpanSource {
virtual void Get(RGBA *span, int x, int y, unsigned len) = 0;
};
class ClipLine : NoCopy {
byte *data;
public:
void Clear() { if(!IsFull()) delete[] data; data = NULL; }
void Set(const byte *s, int len) { data = new byte[len]; memcpy(data, s, len); }
void SetFull() { ASSERT(!data); data = (byte *)1; }
bool IsEmpty() const { return !data; }
bool IsFull() const { return data == (byte *)1; }
operator const byte*() const { return data; }
ClipLine() { data = NULL; }
~ClipLine() { Clear(); }
};
Image MipMap(const Image& img);
Image MakeMipMap(const Image& img, int level);
class LinearInterpolator {
struct Dda2 {
int count, lift, rem, mod, p;
void Set(int a, int b, int len);
int Get();
};
Xform2D xform;
Dda2 ddax, dday;
public:
void Set(const Xform2D& m) { xform = m; }
void Begin(int x, int y, int len);
Point Get();
};
class BufferPainter : public Painter {
protected:
virtual void ClearOp(const RGBA& color);
virtual void MoveOp(const Pointf& p, bool rel);
virtual void LineOp(const Pointf& p, bool rel);
virtual void QuadraticOp(const Pointf& p1, const Pointf& p, bool rel);
virtual void QuadraticOp(const Pointf& p, bool rel);
virtual void CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel);
virtual void CubicOp(const Pointf& p2, const Pointf& p, bool rel);
virtual void ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel);
virtual void SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep,
const Pointf& p, bool rel);
virtual void CloseOp();
virtual void DivOp();
virtual void FillOp(const RGBA& color);
virtual void FillOp(const Image& image, const Xform2D& transsrc, dword flags);
virtual void FillOp(const Pointf& p1, const RGBA& color1,
const Pointf& p2, const RGBA& color2,
int style);
virtual void FillOp(const Pointf& f, const RGBA& color1,
const Pointf& c, double r, const RGBA& color2,
int style);
virtual void StrokeOp(double width, const RGBA& rgba);
virtual void StrokeOp(double width, const Image& image, const Xform2D& transsrc,
dword flags);
virtual void StrokeOp(double width, const Pointf& p1, const RGBA& color1,
const Pointf& p2, const RGBA& color2,
int style);
virtual void StrokeOp(double width, const Pointf& f, const RGBA& color1,
const Pointf& c, double r, const RGBA& color2,
int style);
virtual void ClipOp();
virtual void ColorStopOp(double pos, const RGBA& color);
virtual void ClearStopsOp();
virtual void OpacityOp(double o);
virtual void LineCapOp(int linecap);
virtual void LineJoinOp(int linejoin);
virtual void MiterLimitOp(double l);
virtual void EvenOddOp(bool evenodd);
virtual void DashOp(const Vector<double>& dash, double start);
virtual void NoAAOp(bool noaa);
virtual void TransformOp(const Xform2D& m);
virtual void BeginOp();
virtual void EndOp();
virtual void BeginMaskOp();
public:
enum {
MOVE, LINE, QUADRATIC, CUBIC, DIV
};
struct LinearData {
Pointf p;
};
struct QuadraticData : LinearData {
Pointf p1;
};
struct CubicData : QuadraticData {
Pointf p2;
};
struct Path {
Vector<byte> type;
Vector<byte> data;
};
struct Attr : Moveable<Attr> {
Xform2D mtx;
double tolerance;
bool evenodd;
byte join;
byte cap;
double miter_limit;
WithDeepCopy< Vector<double> > dash;
WithDeepCopy< Vector<double> > stop;
WithDeepCopy< Vector<RGBA> > stop_color;
double dash_start;
double opacity;
int cliplevel;
bool hasclip;
bool mask;
bool noaa;
};
ImageBuffer& ib;
Buffer<int16> subpixel;
int render_cx;
Attr attr;
Attr pathattr;
Array<Attr> attrstack;
Vector< Buffer<ClipLine> > clip;
Array< ImageBuffer > mask;
Image gradient;
RGBA gradient1, gradient2;
int gradientn;
Path path;
Pointf current, ccontrol, qcontrol, move;
Rectf pathrect;
Rasterizer rasterizer;
Buffer<RGBA> span;
void *PathAddRaw(int type, int size);
template <class T> T& PathAdd(int type) { return *(T *)PathAddRaw(type, sizeof(T)); }
Pointf PathPoint(const Pointf& p, bool rel);
Pointf EndPoint(const Pointf& p, bool rel);
void DoMove0();
void ClearPath();
Buffer<ClipLine> RenderPath(double width, SpanSource *ss, const RGBA& color);
void RenderImage(double width, const Image& image, const Xform2D& transsrc,
dword flags);
void RenderRadial(double width, const Pointf& f, const RGBA& color1,
const Pointf& c, double r, const RGBA& color2, int style);
void MakeGradient(RGBA color1, RGBA color2, int cx);
void Gradient(const RGBA& color1, const RGBA& color2, const Pointf& p1, const Pointf& p2);
void ColorStop0(Attr& a, double pos, const RGBA& color);
void FinishMask();
public:
BufferPainter(ImageBuffer& ib, bool subpixel = false);
};

View file

@ -105,13 +105,18 @@ void BufferPainter::ClearStopsOp()
}
}
BufferPainter::BufferPainter(ImageBuffer& ib)
: ib(ib),
rasterizer(ib.GetWidth(), ib.GetHeight())
BufferPainter::BufferPainter(ImageBuffer& ib, bool subpixel_)
: ib(ib),
rasterizer(subpixel_ ? 3 * ib.GetWidth() : ib.GetWidth(), ib.GetHeight())
{
ClearPath();
attr.mtx = Xform2D::Identity();
render_cx = ib.GetWidth();
if(subpixel_) {
render_cx *= 3;
subpixel.Alloc(render_cx + 30);
}
attr.mtx = Xform2D::Scale(subpixel ? 3 : 1, 1);
attr.tolerance = 0.3;
attr.cap = LINECAP_BUTT;
attr.join = LINEJOIN_MITER;

View file

@ -1,272 +1,331 @@
#include "Painter.h"
#include "Fillers.h"
NAMESPACE_UPP
void SolidFiller::Start(int minx, int maxx)
{
t += minx;
}
void SolidFiller::Render(int val)
{
AlphaBlendCover8(*t++, c, val);
}
void SolidFiller::Render(int val, int len)
{
if(val == 0) {
t += len;
return;
}
if(((val - 256) | (c.a - 255)) == 0) {
while(len >= 16) {
t[0] = c; t[1] = c; t[2] = c; t[3] = c;
t[4] = c; t[5] = c; t[6] = c; t[7] = c;
t[8] = c; t[9] = c; t[10] = c; t[11] = c;
t[12] = c; t[13] = c; t[14] = c; t[15] = c;
t += 16;
len -= 16;
}
switch(len) {
case 15: t[14] = c;
case 14: t[13] = c;
case 13: t[12] = c;
case 12: t[11] = c;
case 11: t[10] = c;
case 10: t[9] = c;
case 9: t[8] = c;
case 8: t[7] = c;
case 7: t[6] = c;
case 6: t[5] = c;
case 5: t[4] = c;
case 4: t[3] = c;
case 3: t[2] = c;
case 2: t[1] = c;
case 1: t[0] = c;
}
t += len;
}
else {
RGBA c1;
if(val != 256)
c1 = Mul8(c, val);
else
c1 = c;
RGBA *e = t + len;
while(t < e)
AlphaBlend(*t++, c1);
}
}
void SpanFiller::Start(int minx, int maxx)
{
t += minx;
ss->Get(buffer, minx, y, maxx - minx + 1);
s = buffer;
}
void SpanFiller::Render(int val)
{
if(alpha != 256)
val = alpha * val >> 8;
AlphaBlendCover8(*t++, *s++, val);
}
void SpanFiller::Render(int val, int len)
{
if(val == 0) {
t += len;
s += len;
return;
}
const RGBA *e = t + len;
if(alpha != 256)
val = alpha * val >> 8;
if(val == 256)
while(t < e) {
if(s->a == 255)
*t++ = *s++;
else
AlphaBlend(*t++, *s++);
}
else
while(t < e)
AlphaBlendCover8(*t++, *s++, val);
}
ClipFiller::ClipFiller(int _cx)
{
cx = _cx;
buffer.Alloc(2 * cx);
}
void ClipFiller::Clear()
{
t = ~buffer;
x = 0;
empty = true;
full = true;
last = -1;
}
void ClipFiller::Start(int xmin, int xmax)
{
Render(0, xmin);
}
void ClipFiller::Span(int val, int len)
{
int v = val >> 1;
if(last == val) {
int n = min(v + 128 - *lastn - 1, len);
*lastn += n;
len -= n;
}
last = -1;
while(len > 128) {
int n = min(len, 128);
*t++ = 0;
*t++ = v + n - 1;
len -= n;
}
if(len) {
*t++ = 0;
last = val;
lastn = t;
*t++ = v + len - 1;
}
}
void ClipFiller::Render(int val, int len)
{
if(val == 256) {
Span(256, len);
empty = false;
}
else {
full = false;
if(val == 0)
Span(0, len);
else {
memset(t, val, len);
t += len;
empty = false;
last = -1;
}
}
x += len;
}
void ClipFiller::Render(int val)
{
Render(val, 1);
}
void ClipFiller::Finish(ClipLine& cl)
{
if(empty)
return;
while(x < cx) {
int n = min(cx - x, 128);
*t++ = 0;
*t++ = n - 1;
x += n;
full = false;
}
if(full)
cl.SetFull();
else
cl.Set(~buffer, t - ~buffer);
}
void MaskFillerFilter::Render(int val)
{
for(;;) {
if(empty) {
t->Render(0);
empty--;
return;
}
if(full) {
t->Render(val);
full--;
return;
}
byte m = *mask++;
if(m) {
t->Render(val * m >> 8);
return;
}
m = *mask++;
if(m < 128)
empty = m + 1;
else
full = m - 128 + 1;
}
}
void MaskFillerFilter::Render(int val, int len)
{
while(len)
if(empty) {
int n = min(len, empty);
t->Render(0, n);
empty -= n;
len -= n;
}
else
if(full) {
int n = min(len, full);
t->Render(val, n);
full -= n;
len -= n;
}
else {
byte m = *mask++;
if(m) {
t->Render(val * m >> 8);
len--;
}
else {
m = *mask++;
if(m < 128)
empty = m + 1;
else
full = m - 128 + 1;
}
}
}
struct NilFiller : Rasterizer::Filler {
void Start(int minx, int maxx) {}
void Render(int val, int len) {}
void Render(int val) {}
};
void MaskFillerFilter::Start(int minx, int maxx)
{
t->Start(minx, maxx);
Rasterizer::Filler *h = t;
NilFiller nil;
t = &nil;
Render(0, minx);
t = h;
}
void NoAAFillerFilter::Start(int minx, int maxx)
{
t->Start(minx, maxx);
}
void NoAAFillerFilter::Render(int val, int len)
{
t->Render(val < 128 ? 0 : 256, len);
}
void NoAAFillerFilter::Render(int val)
{
t->Render(val < 128 ? 0 : 256);
}
END_UPP_NAMESPACE
#include "Painter.h"
#include "Fillers.h"
NAMESPACE_UPP
void SolidFiller::Start(int minx, int maxx)
{
t += minx;
}
void SolidFiller::Render(int val)
{
AlphaBlendCover8(*t++, c, val);
}
void SolidFiller::Render(int val, int len)
{
if(val == 0) {
t += len;
return;
}
if(((val - 256) | (c.a - 255)) == 0) {
while(len >= 16) {
t[0] = c; t[1] = c; t[2] = c; t[3] = c;
t[4] = c; t[5] = c; t[6] = c; t[7] = c;
t[8] = c; t[9] = c; t[10] = c; t[11] = c;
t[12] = c; t[13] = c; t[14] = c; t[15] = c;
t += 16;
len -= 16;
}
switch(len) {
case 15: t[14] = c;
case 14: t[13] = c;
case 13: t[12] = c;
case 12: t[11] = c;
case 11: t[10] = c;
case 10: t[9] = c;
case 9: t[8] = c;
case 8: t[7] = c;
case 7: t[6] = c;
case 6: t[5] = c;
case 5: t[4] = c;
case 4: t[3] = c;
case 3: t[2] = c;
case 2: t[1] = c;
case 1: t[0] = c;
}
t += len;
}
else {
RGBA c1;
if(val != 256)
c1 = Mul8(c, val);
else
c1 = c;
RGBA *e = t + len;
while(t < e)
AlphaBlend(*t++, c1);
}
}
void SubpixelFiller::Start(int minx, int maxx)
{
x = minx / 3;
t += x;
v = sbuffer;
int n = minx % 3 + 3;
while(n--)
*v++ = 0;
v[0] = v[1] = v[2] = v[3] = v[4] = 0;
if(ss) {
int xx = maxx / 3;
ss->Get(buffer, x, y, xx - x + 2);
s = buffer;
}
}
void SubpixelFiller::Render(int val)
{
int h = (7282 * val) >> 16;
int h2 = h + h;
v[-2] += h;
v[-1] += h2;
v[0] += val - h2 - h2 - h2;
v[1] += h2;
v[2] += h;
v[3] = 0;
v++;
x++;
}
void SubpixelFiller::Render(int val, int len)
{
while(len--)
Render(val);
}
void SubpixelFiller::End()
{
int16 *q = sbuffer + 3;
while(q < v) {
RGBA c = ss ? Mul8(*s++, alpha) : color;
int a, alpha;
a = c.a * q[0] >> 8;
alpha = 256 - (a + (a >> 7));
t->r = (c.r * q[0] >> 8) + (alpha * t->r >> 8);
a = c.a * q[1] >> 8;
alpha = 256 - (a + (a >> 7));
t->g = (c.g * q[1] >> 8) + (alpha * t->g >> 8);
a = c.a * q[2] >> 8;
alpha = 256 - (a + (a >> 7));
t->b = (c.b * q[2] >> 8) + (alpha * t->b >> 8);
a = c.a * (q[0] + q[1] + q[2]) / 3 >> 8;
alpha = 256 - (a + (a >> 7));
t->a = a + (alpha * t->a >> 8);
t++;
q += 3;
}
}
void SpanFiller::Start(int minx, int maxx)
{
t += minx;
ss->Get(buffer, minx, y, maxx - minx + 1);
s = buffer;
}
void SpanFiller::Render(int val)
{
if(alpha != 256)
val = alpha * val >> 8;
AlphaBlendCover8(*t++, *s++, val);
}
void SpanFiller::Render(int val, int len)
{
if(val == 0) {
t += len;
s += len;
return;
}
const RGBA *e = t + len;
if(alpha != 256)
val = alpha * val >> 8;
if(val == 256)
while(t < e) {
if(s->a == 255)
*t++ = *s++;
else
AlphaBlend(*t++, *s++);
}
else
while(t < e)
AlphaBlendCover8(*t++, *s++, val);
}
ClipFiller::ClipFiller(int _cx)
{
cx = _cx;
buffer.Alloc(2 * cx);
}
void ClipFiller::Clear()
{
t = ~buffer;
x = 0;
empty = true;
full = true;
last = -1;
}
void ClipFiller::Start(int xmin, int xmax)
{
Render(0, xmin);
}
void ClipFiller::Span(int val, int len)
{
int v = val >> 1;
if(last == val) {
int n = min(v + 128 - *lastn - 1, len);
*lastn += n;
len -= n;
}
last = -1;
while(len > 128) {
int n = min(len, 128);
*t++ = 0;
*t++ = v + n - 1;
len -= n;
}
if(len) {
*t++ = 0;
last = val;
lastn = t;
*t++ = v + len - 1;
}
}
void ClipFiller::Render(int val, int len)
{
if(val == 256) {
Span(256, len);
empty = false;
}
else {
full = false;
if(val == 0)
Span(0, len);
else {
memset(t, val, len);
t += len;
empty = false;
last = -1;
}
}
x += len;
}
void ClipFiller::Render(int val)
{
Render(val, 1);
}
void ClipFiller::Finish(ClipLine& cl)
{
if(empty)
return;
while(x < cx) {
int n = min(cx - x, 128);
*t++ = 0;
*t++ = n - 1;
x += n;
full = false;
}
if(full)
cl.SetFull();
else
cl.Set(~buffer, t - ~buffer);
}
void MaskFillerFilter::Render(int val)
{
for(;;) {
if(empty) {
t->Render(0);
empty--;
return;
}
if(full) {
t->Render(val);
full--;
return;
}
byte m = *mask++;
if(m) {
t->Render(val * m >> 8);
return;
}
m = *mask++;
if(m < 128)
empty = m + 1;
else
full = m - 128 + 1;
}
}
void MaskFillerFilter::Render(int val, int len)
{
while(len)
if(empty) {
int n = min(len, empty);
t->Render(0, n);
empty -= n;
len -= n;
}
else
if(full) {
int n = min(len, full);
t->Render(val, n);
full -= n;
len -= n;
}
else {
byte m = *mask++;
if(m) {
t->Render(val * m >> 8);
len--;
}
else {
m = *mask++;
if(m < 128)
empty = m + 1;
else
full = m - 128 + 1;
}
}
}
struct NilFiller : Rasterizer::Filler {
void Start(int minx, int maxx) {}
void Render(int val, int len) {}
void Render(int val) {}
};
void MaskFillerFilter::Start(int minx, int maxx)
{
t->Start(minx, maxx);
Rasterizer::Filler *h = t;
NilFiller nil;
t = &nil;
Render(0, minx);
t = h;
}
void NoAAFillerFilter::Start(int minx, int maxx)
{
t->Start(minx, maxx);
}
void NoAAFillerFilter::Render(int val, int len)
{
t->Render(val < 128 ? 0 : 256, len);
}
void NoAAFillerFilter::Render(int val)
{
t->Render(val < 128 ? 0 : 256);
}
END_UPP_NAMESPACE

View file

@ -22,6 +22,23 @@ struct SpanFiller : Rasterizer::Filler {
void Render(int val, int len);
};
struct SubpixelFiller : Rasterizer::Filler {
int16 *sbuffer;
RGBA *t;
int16 *v;
RGBA *s;
RGBA color;
SpanSource *ss;
int alpha;
RGBA *buffer;
int x, y;
void Start(int minx, int maxx);
void Render(int val);
void Render(int val, int len);
void End();
};
struct ClipFiller : Rasterizer::Filler {
Buffer<byte> buffer;
byte *t;
@ -53,6 +70,7 @@ struct MaskFillerFilter : Rasterizer::Filler {
void Start(int minx, int maxx);
void Render(int val, int len);
void Render(int val);
void End() { t->End(); }
void Set(Rasterizer::Filler *f, const byte *m) { t = f; mask = m; empty = full = 0; }
};
@ -63,6 +81,7 @@ struct NoAAFillerFilter : Rasterizer::Filler {
void Start(int minx, int maxx);
void Render(int val, int len);
void Render(int val);
void End() { t->End(); }
void Set(Rasterizer::Filler *f) { t = f; }
};

View file

@ -220,7 +220,10 @@ void BufferPainter::RenderImage(double width, const Image& image, const Xform2D&
ss.hstyle = byte(flags & 3);
ss.vstyle = byte(flags & 12);
ss.fast = flags & FILL_FAST;
ss.Set(transsrc * pathattr.mtx, image);
Xform2D m = transsrc * pathattr.mtx;
if(subpixel)
m = m * Xform2D::Scale(1 / 3.0, 1);
ss.Set(m, image);
RenderPath(width, &ss, RGBAZero());
}

View file

@ -146,13 +146,10 @@ protected:
static bool ReadBool(CParser& p);
static double ReadDouble(CParser& p);
static Pointf ReadPoint(CParser& p);
void ArcSegment(const Pointf& c, double th0, double th1, const Pointf& r, double xAxisRotation);
void DoArc0(double theta, double th_sweep, const Xform2D& m);
void DoArc(const Pointf& c, const Pointf& r, double angle, double sweep, double xangle);
void DoSvgArc(const Pointf& rr, double xangle, int large, int sweep,
const Pointf& p, const Pointf& p0);
// void DoSvgArc(double rx, double ry, double x_axis_rotation,
// int large_arc_flag, int sweep_flag,
// double x, double y, double curx, double cury);
public:
void Clear(const RGBA& color);

View file

@ -1,131 +1,119 @@
#include "Painter.h"
NAMESPACE_UPP
void BufferPainter::ClearPath()
{
path.type.Clear();
path.data.Clear();
current = move = Null;
ccontrol = qcontrol = Pointf(0, 0);
}
Pointf BufferPainter::PathPoint(const Pointf& p, bool rel)
{
Pointf r;
r.x = IsNull(p.x) ? current.x : rel ? p.x + current.x : p.x;
r.y = IsNull(p.y) ? current.y : rel ? p.y + current.y : p.y;
if(IsNull(current)) {
ClearPath();
pathrect.left = pathrect.right = r.x;
pathrect.top = pathrect.bottom = r.y;
pathattr = attr;
}
else {
pathrect.left = min(pathrect.left, r.x);
pathrect.top = min(pathrect.top, r.y);
pathrect.right = max(pathrect.right, r.x);
pathrect.bottom = max(pathrect.bottom, r.y);
}
return r;
}
Pointf BufferPainter::EndPoint(const Pointf& p, bool rel)
{
return current = PathPoint(p, rel);
}
void *BufferPainter::PathAddRaw(int type, int size)
{
int q = path.data.GetCount();
path.type.Add(type);
path.data.SetCount(q + size);
return &path.data[q];
}
void BufferPainter::MoveOp(const Pointf& p, bool rel)
{
move = ccontrol = qcontrol = EndPoint(p, rel);
PathAdd<LinearData>(MOVE).p = move;
}
void BufferPainter::DoMove0()
{
if(IsNull(move))
MoveOp(Pointf(0, 0), false);
}
void BufferPainter::LineOp(const Pointf& p, bool rel)
{
DoMove0();
PathAdd<LinearData>(LINE).p = ccontrol = qcontrol = EndPoint(p, rel);
}
void BufferPainter::QuadraticOp(const Pointf& p1, const Pointf& p, bool rel)
{
DoMove0();
QuadraticData& m = PathAdd<QuadraticData>(QUADRATIC);
qcontrol = m.p1 = PathPoint(p1, rel);
m.p = EndPoint(p, rel);
}
void BufferPainter::QuadraticOp(const Pointf& p, bool rel)
{
QuadraticOp(2.0 * current - qcontrol, p, rel);
}
void BufferPainter::CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel)
{
DoMove0();
CubicData& m = PathAdd<CubicData>(CUBIC);
m.p1 = PathPoint(p1, rel);
ccontrol = m.p2 = PathPoint(p2, rel);
m.p = EndPoint(p, rel);
}
void BufferPainter::CubicOp(const Pointf& p2, const Pointf& p, bool rel)
{
CubicOp(2.0 * current - ccontrol, p2, p, rel);
}
Pointf BufferPainter::ArcData::EndPoint() const
{
return r * Polar(angle + sweep) + p;
}
void BufferPainter::ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel)
{
DoMove0();
ArcData& m = PathAdd<ArcData>(ARC);
m.p = PathPoint(c, rel);
m.r = r;
m.angle = angle;
m.sweep = sweep;
PathPoint(c + r, rel);
PathPoint(c - r, rel);
current = m.EndPoint();
}
void BufferPainter::SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep,
const Pointf& p, bool rel)
{
DoMove0();
Pointf c = current;
DoSvgArc(r, xangle, large, sweep, EndPoint(p, rel), c);
}
void BufferPainter::CloseOp()
{
if(!IsNull(move) && !IsNull(current) && current != move) {
Line(move);
move = Null;
}
}
void BufferPainter::DivOp()
{
CloseOp();
path.type.Add(DIV);
}
END_UPP_NAMESPACE
#include "Painter.h"
NAMESPACE_UPP
void BufferPainter::ClearPath()
{
path.type.Clear();
path.data.Clear();
current = move = Null;
ccontrol = qcontrol = Pointf(0, 0);
}
Pointf BufferPainter::PathPoint(const Pointf& p, bool rel)
{
Pointf r;
r.x = IsNull(p.x) ? current.x : rel ? p.x + current.x : p.x;
r.y = IsNull(p.y) ? current.y : rel ? p.y + current.y : p.y;
if(IsNull(current)) {
ClearPath();
pathrect.left = pathrect.right = r.x;
pathrect.top = pathrect.bottom = r.y;
pathattr = attr;
}
else {
pathrect.left = min(pathrect.left, r.x);
pathrect.top = min(pathrect.top, r.y);
pathrect.right = max(pathrect.right, r.x);
pathrect.bottom = max(pathrect.bottom, r.y);
}
return r;
}
Pointf BufferPainter::EndPoint(const Pointf& p, bool rel)
{
return current = PathPoint(p, rel);
}
void *BufferPainter::PathAddRaw(int type, int size)
{
int q = path.data.GetCount();
path.type.Add(type);
path.data.SetCount(q + size);
return &path.data[q];
}
void BufferPainter::MoveOp(const Pointf& p, bool rel)
{
move = ccontrol = qcontrol = EndPoint(p, rel);
PathAdd<LinearData>(MOVE).p = move;
}
void BufferPainter::DoMove0()
{
if(IsNull(move))
MoveOp(Pointf(0, 0), false);
}
void BufferPainter::LineOp(const Pointf& p, bool rel)
{
DoMove0();
PathAdd<LinearData>(LINE).p = ccontrol = qcontrol = EndPoint(p, rel);
}
void BufferPainter::QuadraticOp(const Pointf& p1, const Pointf& p, bool rel)
{
DoMove0();
QuadraticData& m = PathAdd<QuadraticData>(QUADRATIC);
qcontrol = m.p1 = PathPoint(p1, rel);
m.p = EndPoint(p, rel);
}
void BufferPainter::QuadraticOp(const Pointf& p, bool rel)
{
QuadraticOp(2.0 * current - qcontrol, p, rel);
}
void BufferPainter::CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel)
{
DoMove0();
CubicData& m = PathAdd<CubicData>(CUBIC);
m.p1 = PathPoint(p1, rel);
ccontrol = m.p2 = PathPoint(p2, rel);
m.p = EndPoint(p, rel);
}
void BufferPainter::CubicOp(const Pointf& p2, const Pointf& p, bool rel)
{
CubicOp(2.0 * current - ccontrol, p2, p, rel);
}
void BufferPainter::ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel)
{
DoMove0();
DoArc(PathPoint(c, rel), r, angle, sweep, 0);
}
void BufferPainter::SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep,
const Pointf& p, bool rel)
{
DoMove0();
Pointf c = current;
DoSvgArc(r, xangle, large, sweep, EndPoint(p, rel), c);
}
void BufferPainter::CloseOp()
{
if(!IsNull(move) && !IsNull(current) && current != move) {
Line(move);
move = Null;
}
}
void BufferPainter::DivOp()
{
CloseOp();
path.type.Add(DIV);
}
END_UPP_NAMESPACE

View file

@ -198,7 +198,10 @@ void BufferPainter::RenderRadial(double width, const Pointf& f, const RGBA& colo
const Pointf& c, double r, const RGBA& color2, int style)
{
PainterRadialSpan sg;
sg.interpolator.Set(Inverse(pathattr.mtx));
Xform2D m = pathattr.mtx;
if(subpixel)
m = m * Xform2D::Scale(1.0 / 3, 1);
sg.interpolator.Set(Inverse(m));
sg.style = style;
sg.Set((int)c.x, (int)c.y, (int)r, (int)f.x, (int)f.y);
MakeGradient(color1, color2, 2048);

View file

@ -1,352 +1,355 @@
#include "Painter.h"
// This code is based in AGG rasterizer with this original information:
//----------------------------------------------------------------------------
// Anti-Grain Geometry - Version 2.4
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
//----------------------------------------------------------------------------
//
// The author gratefully acknowleges the support of David Turner,
// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
// libray - in producing this work. See http://www.freetype.org for details.
//
//----------------------------------------------------------------------------
// Contact: mcseem@antigrain.com
// mcseemagg@yahoo.com
// http://www.antigrain.com
//----------------------------------------------------------------------------
#define LLOG(x) // LOG(x)
NAMESPACE_UPP
void Rasterizer::Init()
{
p0 = Pointf(0, 0);
min_y = INT_MAX;
max_y = INT_MIN;
}
void Rasterizer::Reset()
{
PAINTER_TIMING("Rasterizer::Reset");
for(int i = min_y; i <= max_y; i++)
cell[i].SetCount(0);
Init();
}
void Rasterizer::SetClip(const Rectf& rect)
{
cliprect = rect & Sizef(sz);
}
Rasterizer::Rasterizer(int cx, int cy)
{
sz.cx = cx;
sz.cy = cy;
cell.Alloc(sz.cy + 1);
cliprect = Sizef(sz);
Init();
Reset();
}
inline Rasterizer::Cell *Rasterizer::AddCells(int y, int n)
{
Vector<Cell>& v = cell[y];
if(v.GetAlloc() == 0) {
v.Reserve(16);
v.SetCount(n);
return &v[0];
}
y = v.GetCount();
v.SetCount(y + n);
return &v[y];
}
inline void Rasterizer::RenderHLine(int ey, int x1, int y1, int x2, int y2)
{
int ex1 = x1 >> 8;
int ex2 = x2 >> 8;
int fx1 = x1 & 255;
int fx2 = x2 & 255;
Cell *c;
if(y1 == y2)
return;
int dy = y2 - y1;
if(ex1 == ex2) {
c = AddCells(ey, 1);
c->x = ex1;
c->cover = dy;
c->area = (fx1 + fx2) * dy;
return;
}
int dx = x2 - x1;
if(dx < 0) {
int p = fx1 * dy;
dx = -dx;
int delta = p / dx;
int mod = p % dx;
if(mod < 0) {
delta--;
mod += dx;
}
c = AddCells(ey, abs(ex2 - ex1) + 1);
c->x = ex1;
c->cover = delta;
c->area = fx1 * delta;
c++;
ex1--;
y1 += delta;
if(ex1 != ex2) {
p = (y2 - y1 + delta) * 256;
int lift = p / dx;
int rem = p % dx;
if (rem < 0) {
lift--;
rem += dx;
}
mod -= dx;
while(ex1 != ex2) {
delta = lift;
mod += rem;
if(mod >= 0) {
mod -= dx;
delta++;
}
c->x = ex1;
c->cover = delta;
c->area = delta * 256;
c++;
y1 += delta;
ex1--;
}
}
c->x = ex2;
dy = y2 - y1;
c->cover = dy;
c->area = (fx2 + 256) * dy;
}
else {
int p = (256 - fx1) * dy;
int delta = p / dx;
int mod = p % dx;
if(mod < 0) {
delta--;
mod += dx;
}
c = AddCells(ey, abs(ex2 - ex1) + 1);
c->x = ex1;
c->cover = delta;
c->area = (fx1 + 256) * delta;
c++;
ex1++;
y1 += delta;
if(ex1 != ex2) {
p = (y2 - y1 + delta) * 256;
int lift = p / dx;
int rem = p % dx;
if (rem < 0) {
lift--;
rem += dx;
}
mod -= dx;
while(ex1 != ex2) {
delta = lift;
mod += rem;
if(mod >= 0) {
mod -= dx;
delta++;
}
c->x = ex1;
c->cover = delta;
c->area = delta * 256;
c++;
y1 += delta;
ex1++;
}
}
c->x = ex2;
dy = y2 - y1;
c->cover = dy;
c->area = fx2 * dy;
}
}
void Rasterizer::LineRaw(int x1, int y1, int x2, int y2)
{
PAINTER_TIMING("LineRaw");
LLOG("Rasterizer::LineRaw " << x1 / 256.0 << ':' << y1 / 256.0
<< " - " << x2 / 256.0 << ':' << y2 / 256.0);
int ex1 = x1 >> 8;
int ex2 = x2 >> 8;
int ey1 = y1 >> 8;
int ey2 = y2 >> 8;
ASSERT(ey1 >= 0 && ey1 <= sz.cy && ey2 >= 0 && ey2 <= sz.cy);
if(ey1 < min_y) {
if(ey1 < 0) return;
min_y = ey1;
}
if(ey1 > max_y) {
if(ey1 > sz.cy) return;
max_y = min(ey1, sz.cy - 1);
}
if(ey2 < min_y) {
if(ey2 < 0) return;
min_y = ey2;
}
if(ey2 > max_y) {
if(ey2 > sz.cy) return;
max_y = min(ey2, sz.cy - 1);
}
enum dx_limit_e { dx_limit = 16384 << 8 };
int dx = x2 - x1;
if(dx >= dx_limit || dx <= -dx_limit) {
int cx = (x1 + x2) >> 1;
int cy = (y1 + y2) >> 1;
LineRaw(x1, y1, cx, cy);
LineRaw(cx, cy, x2, y2);
return;
}
int dy = y2 - y1;
int fy1 = y1 & 255;
int fy2 = y2 & 255;
Cell *c;
int x_from, x_to;
int p, rem, mod, lift, delta, first, incr;
if(ey1 == ey2) {
RenderHLine(ey1, x1, fy1, x2, fy2);
return;
}
incr = 1;
if(dx == 0) {
int ex = x1 >> 8;
int two_fx = (x1 - (ex << 8)) << 1;
int area;
first = 256;
if(dy < 0) {
first = 0;
incr = -1;
}
x_from = x1;
delta = first - fy1;
c = AddCells(ey1, 1);
c->x = ex1;
c->cover = delta;
c->area = two_fx * delta;
ey1 += incr;
delta = first + first - 256;
area = two_fx * delta;
while(ey1 != ey2) {
c = AddCells(ey1, 1);
c->x = ex1;
c->cover = delta;
c->area = area;
ey1 += incr;
}
delta = fy2 - 256 + first;
c = AddCells(ey1, 1);
c->x = ex1;
c->cover = delta;
c->area = two_fx * delta;
return;
}
p = (256 - fy1) * dx;
first = 256;
if(dy < 0) {
p = fy1 * dx;
first = 0;
incr = -1;
dy = -dy;
}
delta = p / dy;
mod = p % dy;
if(mod < 0) {
delta--;
mod += dy;
}
x_from = x1 + delta;
RenderHLine(ey1, x1, fy1, x_from, first);
ey1 += incr;
if(ey1 != ey2) {
p = dx << 8;
lift = p / dy;
rem = p % dy;
if(rem < 0) {
lift--;
rem += dy;
}
mod -= dy;
while(ey1 != ey2) {
delta = lift;
mod += rem;
if(mod >= 0) {
mod -= dy;
delta++;
}
x_to = x_from + delta;
RenderHLine(ey1, x_from, 256 - first, x_to, first);
x_from = x_to;
ey1 += incr;
}
}
RenderHLine(ey1, x_from, 256 - first, x2, fy2);
}
void Rasterizer::Render(int y, Rasterizer::Filler& g, bool evenodd)
{
PAINTER_TIMING("Render");
const Cell *c, *e;
if(y < min_y || y > max_y) return;
Vector<Cell>& cl = cell[y];
if(cl.GetCount() == 0) return;
Sort(cl);
c = cl;
e = cl.End();
g.Start(c->x, (e - 1)->x);
int cover = 0;
while(c < e) {
int x = c->x;
int area = c->area;
cover += c->cover;
c++;
while(c < e && c->x == x) {
area += c->area;
cover += c->cover;
c++;
}
if(evenodd) {
if(area) {
int h = abs(((cover << 9) - area) >> 9) & 511;
g.Render(h > 256 ? 512 - h : h);
x++;
}
if(c < e && c->x > x) {
int h = abs(cover) & 511;
g.Render(h > 256 ? 512 - h : h, c->x - x);
}
}
else {
if(area) {
g.Render(min(abs(((cover << 9) - area) >> 9), 256));
x++;
}
if(c < e && c->x > x)
g.Render(min(abs(cover), 256), c->x - x);
}
}
}
END_UPP_NAMESPACE
#include "Painter.h"
// This code is based in AGG rasterizer with this original information:
//----------------------------------------------------------------------------
// Anti-Grain Geometry - Version 2.4
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
//----------------------------------------------------------------------------
//
// The author gratefully acknowleges the support of David Turner,
// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
// libray - in producing this work. See http://www.freetype.org for details.
//
//----------------------------------------------------------------------------
// Contact: mcseem@antigrain.com
// mcseemagg@yahoo.com
// http://www.antigrain.com
//----------------------------------------------------------------------------
#define LLOG(x) // LOG(x)
NAMESPACE_UPP
void Rasterizer::Init()
{
p0 = Pointf(0, 0);
min_y = INT_MAX;
max_y = INT_MIN;
}
void Rasterizer::Reset()
{
PAINTER_TIMING("Rasterizer::Reset");
for(int i = min_y; i <= max_y; i++)
cell[i].SetCount(0);
Init();
}
void Rasterizer::SetClip(const Rectf& rect)
{
cliprect = rect & Sizef(sz);
}
Rasterizer::Rasterizer(int cx, int cy)
{
sz.cx = cx;
sz.cy = cy;
cell.Alloc(sz.cy + 1);
cliprect = Sizef(sz);
Init();
Reset();
}
inline Rasterizer::Cell *Rasterizer::AddCells(int y, int n)
{
Vector<Cell>& v = cell[y];
if(v.GetAlloc() == 0) {
v.Reserve(16);
v.SetCount(n);
return &v[0];
}
y = v.GetCount();
v.SetCount(y + n);
return &v[y];
}
inline void Rasterizer::RenderHLine(int ey, int x1, int y1, int x2, int y2)
{
int ex1 = x1 >> 8;
int ex2 = x2 >> 8;
int fx1 = x1 & 255;
int fx2 = x2 & 255;
Cell *c;
if(y1 == y2)
return;
int dy = y2 - y1;
if(ex1 == ex2) {
c = AddCells(ey, 1);
c->x = ex1;
c->cover = dy;
c->area = (fx1 + fx2) * dy;
return;
}
int dx = x2 - x1;
if(dx < 0) {
int p = fx1 * dy;
dx = -dx;
int delta = p / dx;
int mod = p % dx;
if(mod < 0) {
delta--;
mod += dx;
}
c = AddCells(ey, abs(ex2 - ex1) + 1);
c->x = ex1;
c->cover = delta;
c->area = fx1 * delta;
c++;
ex1--;
y1 += delta;
if(ex1 != ex2) {
p = (y2 - y1 + delta) * 256;
int lift = p / dx;
int rem = p % dx;
if (rem < 0) {
lift--;
rem += dx;
}
mod -= dx;
while(ex1 != ex2) {
delta = lift;
mod += rem;
if(mod >= 0) {
mod -= dx;
delta++;
}
c->x = ex1;
c->cover = delta;
c->area = delta * 256;
c++;
y1 += delta;
ex1--;
}
}
c->x = ex2;
dy = y2 - y1;
c->cover = dy;
c->area = (fx2 + 256) * dy;
}
else {
int p = (256 - fx1) * dy;
int delta = p / dx;
int mod = p % dx;
if(mod < 0) {
delta--;
mod += dx;
}
c = AddCells(ey, abs(ex2 - ex1) + 1);
c->x = ex1;
c->cover = delta;
c->area = (fx1 + 256) * delta;
c++;
ex1++;
y1 += delta;
if(ex1 != ex2) {
p = (y2 - y1 + delta) * 256;
int lift = p / dx;
int rem = p % dx;
if (rem < 0) {
lift--;
rem += dx;
}
mod -= dx;
while(ex1 != ex2) {
delta = lift;
mod += rem;
if(mod >= 0) {
mod -= dx;
delta++;
}
c->x = ex1;
c->cover = delta;
c->area = delta * 256;
c++;
y1 += delta;
ex1++;
}
}
c->x = ex2;
dy = y2 - y1;
c->cover = dy;
c->area = fx2 * dy;
}
}
void Rasterizer::LineRaw(int x1, int y1, int x2, int y2)
{
PAINTER_TIMING("LineRaw");
LLOG("Rasterizer::LineRaw " << x1 / 256.0 << ':' << y1 / 256.0
<< " - " << x2 / 256.0 << ':' << y2 / 256.0);
int ex1 = x1 >> 8;
int ex2 = x2 >> 8;
int ey1 = y1 >> 8;
int ey2 = y2 >> 8;
ASSERT(ey1 >= 0 && ey1 <= sz.cy && ey2 >= 0 && ey2 <= sz.cy);
if(ey1 < min_y) {
if(ey1 < 0) return;
min_y = ey1;
}
if(ey1 > max_y) {
if(ey1 > sz.cy) return;
max_y = min(ey1, sz.cy - 1);
}
if(ey2 < min_y) {
if(ey2 < 0) return;
min_y = ey2;
}
if(ey2 > max_y) {
if(ey2 > sz.cy) return;
max_y = min(ey2, sz.cy - 1);
}
enum dx_limit_e { dx_limit = 16384 << 8 };
int dx = x2 - x1;
if(dx >= dx_limit || dx <= -dx_limit) {
int cx = (x1 + x2) >> 1;
int cy = (y1 + y2) >> 1;
LineRaw(x1, y1, cx, cy);
LineRaw(cx, cy, x2, y2);
return;
}
int dy = y2 - y1;
int fy1 = y1 & 255;
int fy2 = y2 & 255;
Cell *c;
int x_from, x_to;
int p, rem, mod, lift, delta, first, incr;
if(ey1 == ey2) {
RenderHLine(ey1, x1, fy1, x2, fy2);
return;
}
incr = 1;
if(dx == 0) {
int ex = x1 >> 8;
int two_fx = (x1 - (ex << 8)) << 1;
int area;
first = 256;
if(dy < 0) {
first = 0;
incr = -1;
}
x_from = x1;
delta = first - fy1;
c = AddCells(ey1, 1);
c->x = ex1;
c->cover = delta;
c->area = two_fx * delta;
ey1 += incr;
delta = first + first - 256;
area = two_fx * delta;
while(ey1 != ey2) {
c = AddCells(ey1, 1);
c->x = ex1;
c->cover = delta;
c->area = area;
ey1 += incr;
}
delta = fy2 - 256 + first;
c = AddCells(ey1, 1);
c->x = ex1;
c->cover = delta;
c->area = two_fx * delta;
return;
}
p = (256 - fy1) * dx;
first = 256;
if(dy < 0) {
p = fy1 * dx;
first = 0;
incr = -1;
dy = -dy;
}
delta = p / dy;
mod = p % dy;
if(mod < 0) {
delta--;
mod += dy;
}
x_from = x1 + delta;
RenderHLine(ey1, x1, fy1, x_from, first);
ey1 += incr;
if(ey1 != ey2) {
p = dx << 8;
lift = p / dy;
rem = p % dy;
if(rem < 0) {
lift--;
rem += dy;
}
mod -= dy;
while(ey1 != ey2) {
delta = lift;
mod += rem;
if(mod >= 0) {
mod -= dy;
delta++;
}
x_to = x_from + delta;
RenderHLine(ey1, x_from, 256 - first, x_to, first);
x_from = x_to;
ey1 += incr;
}
}
RenderHLine(ey1, x_from, 256 - first, x2, fy2);
}
void Rasterizer::Filler::End() {}
void Rasterizer::Render(int y, Rasterizer::Filler& g, bool evenodd)
{
PAINTER_TIMING("Render");
const Cell *c, *e;
if(y < min_y || y > max_y) return;
Vector<Cell>& cl = cell[y];
if(cl.GetCount() == 0) return;
Sort(cl);
c = cl;
e = cl.End();
g.Start(c->x, (e - 1)->x);
int cover = 0;
while(c < e) {
int x = c->x;
int area = c->area;
cover += c->cover;
c++;
while(c < e && c->x == x) {
area += c->area;
cover += c->cover;
c++;
}
if(evenodd) {
if(area) {
int h = abs(((cover << 9) - area) >> 9) & 511;
g.Render(h > 256 ? 512 - h : h);
x++;
}
if(c < e && c->x > x) {
int h = abs(cover) & 511;
g.Render(h > 256 ? 512 - h : h, c->x - x);
}
}
else {
if(area) {
g.Render(min(abs(((cover << 9) - area) >> 9), 256));
x++;
}
if(c < e && c->x > x)
g.Render(min(abs(cover), 256), c->x - x);
}
}
g.End();
}
END_UPP_NAMESPACE

View file

@ -1,163 +1,173 @@
#include "Painter.h"
#include "Fillers.h"
NAMESPACE_UPP
void BufferPainter::ClearOp(const RGBA& color)
{
UPP::Fill(~ib, color, ib.GetLength());
}
Buffer<ClipLine> BufferPainter::RenderPath(double width, SpanSource *ss, const RGBA& color)
{
Buffer<ClipLine> newclip;
if(width == 0)
return newclip;
Transformer trans(pathattr.mtx);
trans.target = &rasterizer;
LinearPathConsumer *g;
Stroker stroker;
Dasher dasher;
bool evenodd = pathattr.evenodd;
if(width > 0) {
stroker.Init(width, pathattr.miter_limit, pathattr.tolerance, pathattr.cap, pathattr.join);
stroker.target = &trans;
if(pathattr.dash.GetCount()) {
dasher.Init(pathattr.dash, pathattr.dash_start);
dasher.target = &stroker;
g = &dasher;
}
else
g = &stroker;
evenodd = false;
}
else {
Close();
g = &trans;
}
byte *data = path.data;
int opacity = int(256 * pathattr.opacity);
Pointf pos = Pointf(0, 0);
int i = 0;
Rasterizer::Filler *rg;
SpanFiller span_filler;
SolidFiller solid_filler;
ClipFiller clip_filler(ib.GetWidth());
NoAAFillerFilter noaa_filler;
bool doclip = width == -2;
if(doclip) {
rg = &clip_filler;
newclip.Alloc(ib.GetHeight());
}
else
if(ss) {
if(!span)
span.Alloc(ib.GetWidth() + 1);
span_filler.ss = ss;
span_filler.buffer = span;
span_filler.alpha = opacity;
rg = &span_filler;
}
else {
solid_filler.c = Mul8(color, opacity);
rg = &solid_filler;
}
if(pathattr.noaa) {
noaa_filler.Set(rg);
rg = &noaa_filler;
}
for(;;) {
if(i >= path.type.GetCount() || path.type[i] == DIV) {
g->End();
for(int y = rasterizer.MinY(); y <= rasterizer.MaxY(); y++) {
solid_filler.t = span_filler.t = ib[y];
span_filler.y = y;
Rasterizer::Filler *rf = rg;
MaskFillerFilter mf;
if(clip.GetCount()) {
const ClipLine& s = clip.Top()[y];
if(s.IsEmpty()) goto empty;
if(!s.IsFull()) {
mf.Set(rg, s);
rf = &mf;
}
}
if(doclip)
clip_filler.Clear();
rasterizer.Render(y, *rf, evenodd);
if(doclip)
clip_filler.Finish(newclip[y]);
empty:;
}
rasterizer.Reset();
if(i >= path.type.GetCount())
break;
}
else
switch(path.type[i]) {
case MOVE: {
const LinearData *d = (LinearData *)data;
data += sizeof(LinearData);
g->Move(pos = d->p);
break;
}
case LINE: {
const LinearData *d = (LinearData *)data;
data += sizeof(LinearData);
g->Line(pos = d->p);
break;
}
case QUADRATIC: {
const QuadraticData *d = (QuadraticData *)data;
data += sizeof(QuadraticData);
ApproximateQuadratic(*g, pos, d->p1, d->p, pathattr.tolerance);
pos = d->p;
break;
}
case CUBIC: {
const CubicData *d = (CubicData *)data;
data += sizeof(CubicData);
ApproximateCubic(*g, pos, d->p1, d->p2, d->p, pathattr.tolerance);
pos = d->p;
break;
}
case ARC: {
const ArcData *d = (ArcData *)data;
data += sizeof(ArcData);
ApproximateArc(*g, d->p, d->r, d->angle, d->sweep, pathattr.tolerance);
pos = d->EndPoint();
break;
}
default:
NEVER();
return newclip;
}
i++;
}
current = Null;
return newclip;
}
void BufferPainter::FillOp(const RGBA& color)
{
RenderPath(-1, NULL, color);
}
void BufferPainter::StrokeOp(double width, const RGBA& color)
{
RenderPath(width, NULL, color);
}
void BufferPainter::ClipOp()
{
Buffer<ClipLine> newclip = RenderPath(-2, NULL, RGBAZero());
if(attr.hasclip)
clip.Top() = newclip;
else {
clip.Add() = newclip;
attr.hasclip = true;
attr.cliplevel = clip.GetCount();
}
}
END_UPP_NAMESPACE
#include "Painter.h"
#include "Fillers.h"
NAMESPACE_UPP
void BufferPainter::ClearOp(const RGBA& color)
{
UPP::Fill(~ib, color, ib.GetLength());
}
Buffer<ClipLine> BufferPainter::RenderPath(double width, SpanSource *ss, const RGBA& color)
{
Buffer<ClipLine> newclip;
if(width == 0)
return newclip;
Transformer trans(pathattr.mtx);
trans.target = &rasterizer;
LinearPathConsumer *g;
Stroker stroker;
Dasher dasher;
bool evenodd = pathattr.evenodd;
if(width > 0) {
stroker.Init(width, pathattr.miter_limit, pathattr.tolerance, pathattr.cap, pathattr.join);
stroker.target = &trans;
if(pathattr.dash.GetCount()) {
dasher.Init(pathattr.dash, pathattr.dash_start);
dasher.target = &stroker;
g = &dasher;
}
else
g = &stroker;
evenodd = false;
}
else {
Close();
g = &trans;
}
byte *data = path.data;
int opacity = int(256 * pathattr.opacity);
Pointf pos = Pointf(0, 0);
int i = 0;
Rasterizer::Filler *rg;
SpanFiller span_filler;
SolidFiller solid_filler;
SubpixelFiller subpixel_filler;
ClipFiller clip_filler(render_cx);
NoAAFillerFilter noaa_filler;
MaskFillerFilter mf;
bool doclip = width == -2;
subpixel_filler.sbuffer = subpixel;
if(doclip) {
rg = &clip_filler;
newclip.Alloc(ib.GetHeight());
}
else
if(ss) {
if(!span)
span.Alloc(ib.GetWidth() + 3);
if(subpixel) {
subpixel_filler.ss = ss;
subpixel_filler.buffer = span;
subpixel_filler.alpha = opacity;
rg = &subpixel_filler;
}
else {
span_filler.ss = ss;
span_filler.buffer = span;
span_filler.alpha = opacity;
rg = &span_filler;
}
}
else {
if(subpixel) {
subpixel_filler.color = Mul8(color, opacity);
subpixel_filler.ss = NULL;
rg = &subpixel_filler;
}
else {
solid_filler.c = Mul8(color, opacity);
rg = &solid_filler;
}
}
if(pathattr.noaa) {
noaa_filler.Set(rg);
rg = &noaa_filler;
}
for(;;) {
if(i >= path.type.GetCount() || path.type[i] == DIV) {
g->End();
for(int y = rasterizer.MinY(); y <= rasterizer.MaxY(); y++) {
solid_filler.t = subpixel_filler.t = span_filler.t = ib[y];
span_filler.y = subpixel_filler.y = y;
Rasterizer::Filler *rf = rg;
if(clip.GetCount()) {
const ClipLine& s = clip.Top()[y];
if(s.IsEmpty()) goto empty;
if(!s.IsFull()) {
mf.Set(rg, s);
rf = &mf;
}
}
if(doclip)
clip_filler.Clear();
rasterizer.Render(y, *rf, evenodd);
if(doclip)
clip_filler.Finish(newclip[y]);
empty:;
}
rasterizer.Reset();
if(i >= path.type.GetCount())
break;
}
else
switch(path.type[i]) {
case MOVE: {
const LinearData *d = (LinearData *)data;
data += sizeof(LinearData);
g->Move(pos = d->p);
break;
}
case LINE: {
const LinearData *d = (LinearData *)data;
data += sizeof(LinearData);
g->Line(pos = d->p);
break;
}
case QUADRATIC: {
const QuadraticData *d = (QuadraticData *)data;
data += sizeof(QuadraticData);
ApproximateQuadratic(*g, pos, d->p1, d->p, pathattr.tolerance);
pos = d->p;
break;
}
case CUBIC: {
const CubicData *d = (CubicData *)data;
data += sizeof(CubicData);
ApproximateCubic(*g, pos, d->p1, d->p2, d->p, pathattr.tolerance);
pos = d->p;
break;
}
default:
NEVER();
return newclip;
}
i++;
}
current = Null;
return newclip;
}
void BufferPainter::FillOp(const RGBA& color)
{
RenderPath(-1, NULL, color);
}
void BufferPainter::StrokeOp(double width, const RGBA& color)
{
RenderPath(width, NULL, color);
}
void BufferPainter::ClipOp()
{
Buffer<ClipLine> newclip = RenderPath(-2, NULL, RGBAZero());
if(attr.hasclip)
clip.Top() = newclip;
else {
clip.Add() = newclip;
attr.hasclip = true;
attr.cliplevel = clip.GetCount();
}
}
END_UPP_NAMESPACE

View file

@ -2,6 +2,30 @@
NAMESPACE_UPP
void Painter::DoArc0(double theta, double th_sweep, const Xform2D& m)
{
int nsegs = int(ceil(fabs(th_sweep / (M_PI * 0.5 + 0.001))));
for(int i = 0; i < nsegs; i++) {
double th0 = theta + i * th_sweep / nsegs;
double th1 = theta + (i + 1) * th_sweep / nsegs;
double thHalf = 0.5 * (th1 - th0);
double t = (8.0 / 3.0) * sin(thHalf * 0.5) * sin(thHalf * 0.5) / sin(thHalf);
double x3 = cos(th1);
double y3 = sin(th1);
Cubic(m.Transform(cos(th0) - t * sin(th0), sin(th0) + t * cos(th0)),
m.Transform(x3 + t * sin(th1), y3 - t * cos(th1)),
m.Transform(x3, y3));
}
}
void Painter::DoArc(const Pointf& c, const Pointf& r, double angle, double sweep, double xangle)
{
Xform2D m = Xform2D::Scale(r.x, r.y);
m = m * Xform2D::Translation(c.x, c.y);
Line(m.Transform(cos(angle), sin(angle)));
DoArc0(angle, sweep, m);
}
void Painter::DoSvgArc(const Pointf& rr, double xangle, int large, int sweep,
const Pointf& p1, const Pointf& p0)
{
@ -33,21 +57,11 @@ void Painter::DoSvgArc(const Pointf& rr, double xangle, int large, int sweep,
else
if(th_sweep > 0 && !sweep)
th_sweep -= 2 * M_PI;
int nsegs = int(ceil(fabs(th_sweep / (M_PI * 0.5 + 0.001))));
m = Xform2D::Rotation(xangle);
m.x *= r;
m.y *= r;
for(int i = 0; i < nsegs; i++) {
double th0 = theta + i * th_sweep / nsegs;
double th1 = theta + (i + 1) * th_sweep / nsegs;
double thHalf = 0.5 * (th1 - th0);
double t = (8.0 / 3.0) * sin(thHalf * 0.5) * sin(thHalf * 0.5) / sin(thHalf);
double x3 = c.x + cos(th1);
double y3 = c.y + sin(th1);
Cubic(m.Transform(c.x + cos(th0) - t * sin(th0), c.y + sin(th0) + t * cos(th0)),
m.Transform(x3 + t * sin(th1), y3 - t * cos(th1)),
m.Transform(x3, y3));
}
m = Xform2D::Translation(c.x, c.y) * m;
DoArc0(theta, th_sweep, m);
}
END_UPP_NAMESPACE

View file

@ -1,115 +1,114 @@
#include "Painter.h"
NAMESPACE_UPP
Pointf Xform2D::Transform(const Pointf& f) const
{
return Pointf(f.x * x.x + f.y * x.y + t.x, f.x * y.x + f.y * y.y + t.y);
}
Pointf Xform2D::Transform(double x, double y) const
{
return Transform(Pointf(x, y));
}
Pointf Xform2D::GetScaleXY() const
{
return Pointf(sqrt(x.x * x.x + y.x * y.x), sqrt(x.y * x.y + y.y * y.y));
}
double Xform2D::GetScale() const
{
Pointf d = GetScaleXY();
return Length(d) / M_SQRT2;
}
bool Xform2D::IsRegular() const
{
Pointf d = GetScaleXY();
return fabs(d.x - d.y) < 1e-10 * fabs(max(d.x, d.y));
}
Xform2D::Xform2D()
{
x.x = y.y = 1;
x.y = y.x = t.x = t.y = 0;
}
Xform2D operator*(const Xform2D& a, const Xform2D& b)
{
Xform2D r;
r.x.x = a.x.x * b.x.x + a.y.x * b.x.y;
r.x.y = a.x.y * b.x.x + a.y.y * b.x.y;
r.y.x = a.x.x * b.y.x + a.y.x * b.y.y;
r.y.y = a.x.y * b.y.x + a.y.y * b.y.y;
r.t.x = a.t.x * b.x.x + a.t.y * b.x.y + b.t.x;
r.t.y = a.t.x * b.y.x + a.t.y * b.y.y + b.t.y;
return r;
}
Xform2D Xform2D::Translation(double x, double y)
{
Xform2D m;
m.x.x = m.y.y = 1;
m.t = Pointf(x, y);
return m;
}
Xform2D Xform2D::Scale(double sx, double sy)
{
Xform2D m;
m.x.x = sx;
m.y.y = sy;
return m;
}
Xform2D Xform2D::Scale(double scale)
{
return Scale(scale, scale);
}
Xform2D Xform2D::Rotation(double fi)
{
double cosf = cos(fi);
double sinf = sin(fi);
Xform2D m;
m.x.x = cosf;
m.x.y = -sinf;
m.y.x = sinf;
m.y.y = cosf;
m.t.x = m.t.y = 0;
return m;
}
Xform2D Xform2D::Sheer(double fi)
{
Xform2D m;
m.x.x = m.y.y = 1;
m.x.y = atan(fi);
return m;
}
Xform2D Xform2D::Identity()
{
Xform2D m;
m.x.x = m.y.y = 1;
return m;
}
double Determinant(const Xform2D& m)
{
return m.x.x * m.y.y - m.y.x * m.x.y;
}
Xform2D Inverse(const Xform2D& m)
{
Xform2D r;
double det = Determinant(m);
r.x = Pointf(m.y.y, -m.x.y) / det;
r.y = Pointf(-m.y.x, m.x.x) / det;
r.t.x = -m.t.x * r.x.x - m.t.y * r.x.y;
r.t.y = -m.t.x * r.y.x - m.t.y * r.y.y;
return r;
}
END_UPP_NAMESPACE
#include "Painter.h"
NAMESPACE_UPP
Pointf Xform2D::Transform(const Pointf& f) const
{
return Pointf(f.x * x.x + f.y * x.y + t.x, f.x * y.x + f.y * y.y + t.y);
}
Pointf Xform2D::Transform(double x, double y) const
{
return Transform(Pointf(x, y));
}
Pointf Xform2D::GetScaleXY() const
{
return Pointf(sqrt(x.x * x.x + y.x * y.x), sqrt(x.y * x.y + y.y * y.y));
}
double Xform2D::GetScale() const
{
Pointf d = GetScaleXY();
return Length(d) / M_SQRT2;
}
bool Xform2D::IsRegular() const
{
Pointf d = GetScaleXY();
return fabs(d.x - d.y) < 1e-10 * fabs(max(d.x, d.y));
}
Xform2D::Xform2D()
{
x.x = y.y = 1;
x.y = y.x = t.x = t.y = 0;
}
Xform2D operator*(const Xform2D& a, const Xform2D& b)
{
Xform2D r;
r.x.x = a.x.x * b.x.x + a.y.x * b.x.y;
r.x.y = a.x.y * b.x.x + a.y.y * b.x.y;
r.y.x = a.x.x * b.y.x + a.y.x * b.y.y;
r.y.y = a.x.y * b.y.x + a.y.y * b.y.y;
r.t.x = a.t.x * b.x.x + a.t.y * b.x.y + b.t.x;
r.t.y = a.t.x * b.y.x + a.t.y * b.y.y + b.t.y;
return r;
}
Xform2D Xform2D::Translation(double x, double y)
{
Xform2D m;
m.x.x = m.y.y = 1;
m.t = Pointf(x, y);
return m;
}
Xform2D Xform2D::Scale(double sx, double sy)
{
Xform2D m;
m.x.x = sx;
m.y.y = sy;
return m;
}
Xform2D Xform2D::Scale(double scale)
{
return Scale(scale, scale);
}
Xform2D Xform2D::Rotation(double fi)
{
double cosf = cos(fi);
double sinf = sin(fi);
Xform2D m;
m.x.x = cosf;
m.x.y = -sinf;
m.y.x = sinf;
m.y.y = cosf;
m.t.x = m.t.y = 0;
return m;
}
Xform2D Xform2D::Sheer(double fi)
{
Xform2D m;
m.x.x = m.y.y = 1;
m.x.y = atan(fi);
return m;
}
Xform2D Xform2D::Identity()
{
Xform2D m;
return m;
}
double Determinant(const Xform2D& m)
{
return m.x.x * m.y.y - m.y.x * m.x.y;
}
Xform2D Inverse(const Xform2D& m)
{
Xform2D r;
double det = Determinant(m);
r.x = Pointf(m.y.y, -m.x.y) / det;
r.y = Pointf(-m.y.x, m.x.x) / det;
r.t.x = -m.t.x * r.x.x - m.t.y * r.x.y;
r.t.y = -m.t.x * r.y.x - m.t.y * r.y.y;
return r;
}
END_UPP_NAMESPACE