Painter fixed to work in Linux, MoveableWithSwap removed (GCC problems, possibly undefined behaviour of code)

git-svn-id: svn://ultimatepp.org/upp/trunk@867 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2009-02-15 13:11:54 +00:00
parent f2f2348907
commit dd88989c82
13 changed files with 2005 additions and 2045 deletions

View file

@ -1,89 +1,89 @@
#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(abs(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);
}
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

View file

@ -1,352 +1,352 @@
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 : MoveableWithSwap<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);
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);
};

View file

@ -1,272 +1,272 @@
#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 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

@ -1,65 +1,65 @@
#include "Painter.h"
NAMESPACE_UPP
void BufferPainter::MakeGradient(RGBA color1, RGBA color2, int n)
{
if(n == gradientn && color1 == gradient1 && color2 == gradient2)
return;
gradientn = n;
gradient1 = color1;
gradient2 = color2;
ImageBuffer ib(n, 1);
RGBA *t = ib[0];
int l = 0;
RGBA cl = color1;
for(int i = 0; i <= pathattr.stop.GetCount(); i++) {
int h;
RGBA ch;
if(i < pathattr.stop.GetCount()) {
h = (int)(pathattr.stop[i] * (n - 1));
ch = pathattr.stop_color[i];
}
else {
h = n - 1;
ch = color2;
}
int w = h - l;
for(int j = 0; j < w; j++) {
t->r = ((w - j) * cl.r + j * ch.r) / w;
t->g = ((w - j) * cl.g + j * ch.g) / w;
t->b = ((w - j) * cl.b + j * ch.b) / w;
t->a = ((w - j) * cl.a + j * ch.a) / w;
t++;
}
cl = ch;
l = h;
}
*t = cl;
gradient = ib;
}
void BufferPainter::Gradient(const RGBA& color1, const RGBA& color2, const Pointf& p1, const Pointf& p2)
{
MakeGradient(color1, color2, minmax(int(Distance(p1, p2) * pathattr.mtx.GetScale()), 2, 4096));
}
void BufferPainter::FillOp(const Pointf& p1, const RGBA& color1, const Pointf& p2, const RGBA& color2, int style)
{
Gradient(color1, color2, p1, p2);
Fill(gradient, p1, p2,
FILL_VPAD | FILL_FAST |
(style == GRADIENT_PAD ? FILL_HPAD : style == GRADIENT_REPEAT
? FILL_HREPEAT : FILL_HREFLECT));
}
void BufferPainter::StrokeOp(double width, const Pointf& p1, const RGBA& color1, const Pointf& p2, const RGBA& color2, int style)
{
Gradient(color1, color2, p1, p2);
Stroke(width, gradient, p1, p2,
FILL_VPAD | FILL_FAST |
(style == GRADIENT_PAD ? FILL_HPAD : style == GRADIENT_REPEAT
? FILL_HREPEAT : FILL_HREFLECT));
}
END_UPP_NAMESPACE
#include "Painter.h"
NAMESPACE_UPP
void BufferPainter::MakeGradient(RGBA color1, RGBA color2, int n)
{
if(n == gradientn && color1 == gradient1 && color2 == gradient2)
return;
gradientn = n;
gradient1 = color1;
gradient2 = color2;
ImageBuffer ib(n, 1);
RGBA *t = ib[0];
int l = 0;
RGBA cl = color1;
for(int i = 0; i <= pathattr.stop.GetCount(); i++) {
int h;
RGBA ch;
if(i < pathattr.stop.GetCount()) {
h = (int)(pathattr.stop[i] * (n - 1));
ch = pathattr.stop_color[i];
}
else {
h = n - 1;
ch = color2;
}
int w = h - l;
for(int j = 0; j < w; j++) {
t->r = ((w - j) * cl.r + j * ch.r) / w;
t->g = ((w - j) * cl.g + j * ch.g) / w;
t->b = ((w - j) * cl.b + j * ch.b) / w;
t->a = ((w - j) * cl.a + j * ch.a) / w;
t++;
}
cl = ch;
l = h;
}
*t = cl;
gradient = ib;
}
void BufferPainter::Gradient(const RGBA& color1, const RGBA& color2, const Pointf& p1, const Pointf& p2)
{
MakeGradient(color1, color2, minmax(int(Distance(p1, p2) * pathattr.mtx.GetScale()), 2, 4096));
}
void BufferPainter::FillOp(const Pointf& p1, const RGBA& color1, const Pointf& p2, const RGBA& color2, int style)
{
Gradient(color1, color2, p1, p2);
Fill(gradient, p1, p2,
FILL_VPAD | FILL_FAST |
(style == GRADIENT_PAD ? FILL_HPAD : style == GRADIENT_REPEAT
? FILL_HREPEAT : FILL_HREFLECT));
}
void BufferPainter::StrokeOp(double width, const Pointf& p1, const RGBA& color1, const Pointf& p2, const RGBA& color2, int style)
{
Gradient(color1, color2, p1, p2);
Stroke(width, gradient, p1, p2,
FILL_VPAD | FILL_FAST |
(style == GRADIENT_PAD ? FILL_HPAD : style == GRADIENT_REPEAT
? FILL_HREPEAT : FILL_HREFLECT));
}
END_UPP_NAMESPACE

View file

@ -1,238 +1,238 @@
#include "Painter.h"
NAMESPACE_UPP
#if 0 // does not seem to help...
Image MipMap(const Image& img)
{
Size ssz = img.GetSize() / 2;
Size msz = (img.GetSize() + 1) / 2;
ImageBuffer ib(msz);
for(int y = 0; y < ssz.cy; y++) {
const RGBA *s1 = img[2 * y];
const RGBA *s2 = img[2 * y + 1];
const RGBA *e = s1 + 2 * ssz.cx;
RGBA *t = ib[y];
while(s1 < e) {
t->r = (s1[0].r + s1[1].r + s2[0].r + s2[1].r) >> 2;
t->g = (s1[0].g + s1[1].g + s2[0].g + s2[1].g) >> 2;
t->b = (s1[0].b + s1[1].b + s2[0].b + s2[1].b) >> 2;
t->a = (s1[0].a + s1[1].a + s2[0].a + s2[1].a) >> 2;
t++;
s1 += 2;
s2 += 2;
}
if(ssz.cx < msz.cx) {
t->r = (s1[0].r + s2[0].r) >> 2;
t->g = (s1[0].g + s2[0].g) >> 2;
t->b = (s1[0].b + s2[0].b) >> 2;
t->a = (s1[0].a + s2[0].a) >> 2;
}
}
if(ssz.cy < msz.cy) {
const RGBA *s1 = img[img.GetSize().cy - 1];
const RGBA *e = s1 + 2 * ssz.cx;
RGBA *t = ib[msz.cy - 1];
while(s1 < e) {
t->r = (s1[0].r + s1[1].r) >> 2;
t->g = (s1[0].g + s1[1].g) >> 2;
t->b = (s1[0].b + s1[1].b) >> 2;
t->a = (s1[0].a + s1[1].a) >> 2;
t++;
s1 += 2;
}
if(ssz.cx < msz.cx) {
t->r = s1[0].r >> 2;
t->g = s1[0].g >> 2;
t->b = s1[0].b >> 2;
t->a = s1[0].a >> 2;
}
}
return ib;
}
Image MakeMipMap(const Image& m, int level);
struct MipMapMaker : ImageMaker {
int level;
Image image;
virtual String Key() const {
String h;
RawCat(h, image.GetSerialId());
RawCat(h, level);
return h;
}
virtual Image Make() const {
Size sz = image.GetSize();
if(sz.cx && sz.cx) {
if(level <= 0)
return image;
return MipMap(MakeMipMap(image, level - 1));
}
return Image();
}
};
Image MakeMipMap(const Image& img, int level)
{
MipMapMaker m;
m.image = img;
m.level = level;
return MakeImage(m);
}
#endif
struct PainterImageSpan : SpanSource {
struct RGBAV {
dword r, g, b, a;
void Set(dword v) { r = g = b = a = v; }
void Put(dword weight, const RGBA& src) {
r += weight * src.r;
g += weight * src.g;
b += weight * src.b;
a += weight * src.a;
}
};
LinearInterpolator interpolator;
int ax, ay, cx, cy, maxx, maxy;
byte style;
byte hstyle, vstyle;
bool fast;
bool fixed;
Image image;
void Set(const Xform2D& m, const Image& img) {
int level = 0;
#if 0 // no mipmap for now
double q = 1;
if(!fast) {
double q = 1;
Pointf sc = m.GetScaleXY();
if(sc.x >= 0.01 && sc.y >= 0.01)
while(sc.x < 0.5 && sc.y < 0.5) {
level++;
sc.x *= 2;
sc.y *= 2;
q /= 2;
}
}
if(q != 1)
interpolator.Set(Inverse(m) * Xform2D::Scale(q));
else
#endif
interpolator.Set(Inverse(m));
image = img;
// image = MakeMipMap(img, level);
cx = image.GetWidth();
cy = image.GetHeight();
maxx = cx - 1;
maxy = cy - 1;
ax = 6000000 / cx * cx * 2;
ay = 6000000 / cy * cy * 2;
}
RGBA Pixel(int x, int y) { return image[y][x]; }
RGBA GetPixel(int x, int y) {
if(hstyle == FILL_HPAD)
x = minmax(x, 0, maxx);
else
if(hstyle == FILL_HREFLECT)
x = (x + ax) / cx & 1 ? (ax - x - 1) % cx : (x + ax) % cx;
else
if(hstyle == FILL_HREPEAT)
x = (x + ax) % cx;
if(vstyle == FILL_VPAD)
y = minmax(y, 0, maxy);
else
if(vstyle == FILL_VREFLECT)
y = (y + ay) / cy & 1 ? (ay - y - 1) % cy : (y + ay) % cy;
else
if(vstyle == FILL_VREPEAT)
y = (y + ay) % cy;
return fixed || (x >= 0 && x < cx && y >= 0 && y < cy) ? image[y][x] : RGBAZero();
}
virtual void Get(RGBA *span, int x, int y, unsigned len)
{
interpolator.Begin(x, y, len);
fixed = hstyle && vstyle;
while(len--) {
Point h = interpolator.Get();
// h -= 128;
Point l = h >> 8;
if(hstyle == FILL_HREPEAT)
l.x = (l.x + ax) % cx;
if(vstyle == FILL_VREPEAT)
l.y = (l.y + ay) % cy;
if(fast) {
if(l.x > 0 && l.x < maxx && l.y > 0 && l.y < maxy)
*span = Pixel(l.x, l.y);
else
if(style == 0 && (l.x < -1 || l.x > cx || l.y < -1 || l.y > cy))
*span = RGBAZero();
else
*span = GetPixel(l.x, l.y);
}
else {
RGBAV v;
v.Set(0);
// v.Set(256 * 256 / 2);
h.x &= 255;
h.y &= 255;
Point u = -h + 256;
if(l.x > 0 && l.x < maxx && l.y > 0 && l.y < maxy) {
v.Put(u.x * u.y, Pixel(l.x, l.y));
v.Put(h.x * u.y, Pixel(l.x + 1, l.y));
v.Put(u.x * h.y, Pixel(l.x, l.y + 1));
v.Put(h.x * h.y, Pixel(l.x + 1, l.y + 1));
}
else
if(style == 0 && (l.x < -1 || l.x > cx || l.y < -1 || l.y > cy))
v.Set(0);
else {
v.Put(u.x * u.y, GetPixel(l.x, l.y));
v.Put(h.x * u.y, GetPixel(l.x + 1, l.y));
v.Put(u.x * h.y, GetPixel(l.x, l.y + 1));
v.Put(h.x * h.y, GetPixel(l.x + 1, l.y + 1));
}
span->r = byte(v.r >> 16);
span->g = byte(v.g >> 16);
span->b = byte(v.b >> 16);
span->a = byte(v.a >> 16);
}
++span;
}
}
};
void BufferPainter::RenderImage(double width, const Image& image, const Xform2D& transsrc, dword flags)
{
Close();
if(image.GetWidth() == 0 || image.GetHeight() == 0)
return;
PainterImageSpan ss;
ss.style = flags & 15;
ss.hstyle = flags & 3;
ss.vstyle = flags & 12;
ss.fast = flags & FILL_FAST;
ss.Set(transsrc * pathattr.mtx, image);
RenderPath(width, &ss, RGBAZero());
}
void BufferPainter::FillOp(const Image& image, const Xform2D& transsrc, dword flags)
{
RenderImage(-1, image, transsrc, flags);
}
void BufferPainter::StrokeOp(double width, const Image& image, const Xform2D& transsrc, dword flags)
{
RenderImage(width, image, transsrc, flags);
}
END_UPP_NAMESPACE
#include "Painter.h"
NAMESPACE_UPP
#if 0 // does not seem to help...
Image MipMap(const Image& img)
{
Size ssz = img.GetSize() / 2;
Size msz = (img.GetSize() + 1) / 2;
ImageBuffer ib(msz);
for(int y = 0; y < ssz.cy; y++) {
const RGBA *s1 = img[2 * y];
const RGBA *s2 = img[2 * y + 1];
const RGBA *e = s1 + 2 * ssz.cx;
RGBA *t = ib[y];
while(s1 < e) {
t->r = (s1[0].r + s1[1].r + s2[0].r + s2[1].r) >> 2;
t->g = (s1[0].g + s1[1].g + s2[0].g + s2[1].g) >> 2;
t->b = (s1[0].b + s1[1].b + s2[0].b + s2[1].b) >> 2;
t->a = (s1[0].a + s1[1].a + s2[0].a + s2[1].a) >> 2;
t++;
s1 += 2;
s2 += 2;
}
if(ssz.cx < msz.cx) {
t->r = (s1[0].r + s2[0].r) >> 2;
t->g = (s1[0].g + s2[0].g) >> 2;
t->b = (s1[0].b + s2[0].b) >> 2;
t->a = (s1[0].a + s2[0].a) >> 2;
}
}
if(ssz.cy < msz.cy) {
const RGBA *s1 = img[img.GetSize().cy - 1];
const RGBA *e = s1 + 2 * ssz.cx;
RGBA *t = ib[msz.cy - 1];
while(s1 < e) {
t->r = (s1[0].r + s1[1].r) >> 2;
t->g = (s1[0].g + s1[1].g) >> 2;
t->b = (s1[0].b + s1[1].b) >> 2;
t->a = (s1[0].a + s1[1].a) >> 2;
t++;
s1 += 2;
}
if(ssz.cx < msz.cx) {
t->r = s1[0].r >> 2;
t->g = s1[0].g >> 2;
t->b = s1[0].b >> 2;
t->a = s1[0].a >> 2;
}
}
return ib;
}
Image MakeMipMap(const Image& m, int level);
struct MipMapMaker : ImageMaker {
int level;
Image image;
virtual String Key() const {
String h;
RawCat(h, image.GetSerialId());
RawCat(h, level);
return h;
}
virtual Image Make() const {
Size sz = image.GetSize();
if(sz.cx && sz.cx) {
if(level <= 0)
return image;
return MipMap(MakeMipMap(image, level - 1));
}
return Image();
}
};
Image MakeMipMap(const Image& img, int level)
{
MipMapMaker m;
m.image = img;
m.level = level;
return MakeImage(m);
}
#endif
struct PainterImageSpan : SpanSource {
struct RGBAV {
dword r, g, b, a;
void Set(dword v) { r = g = b = a = v; }
void Put(dword weight, const RGBA& src) {
r += weight * src.r;
g += weight * src.g;
b += weight * src.b;
a += weight * src.a;
}
};
LinearInterpolator interpolator;
int ax, ay, cx, cy, maxx, maxy;
byte style;
byte hstyle, vstyle;
bool fast;
bool fixed;
Image image;
void Set(const Xform2D& m, const Image& img) {
int level = 0;
#if 0 // no mipmap for now
double q = 1;
if(!fast) {
double q = 1;
Pointf sc = m.GetScaleXY();
if(sc.x >= 0.01 && sc.y >= 0.01)
while(sc.x < 0.5 && sc.y < 0.5) {
level++;
sc.x *= 2;
sc.y *= 2;
q /= 2;
}
}
if(q != 1)
interpolator.Set(Inverse(m) * Xform2D::Scale(q));
else
#endif
interpolator.Set(Inverse(m));
image = img;
// image = MakeMipMap(img, level);
cx = image.GetWidth();
cy = image.GetHeight();
maxx = cx - 1;
maxy = cy - 1;
ax = 6000000 / cx * cx * 2;
ay = 6000000 / cy * cy * 2;
}
RGBA Pixel(int x, int y) { return image[y][x]; }
RGBA GetPixel(int x, int y) {
if(hstyle == FILL_HPAD)
x = minmax(x, 0, maxx);
else
if(hstyle == FILL_HREFLECT)
x = (x + ax) / cx & 1 ? (ax - x - 1) % cx : (x + ax) % cx;
else
if(hstyle == FILL_HREPEAT)
x = (x + ax) % cx;
if(vstyle == FILL_VPAD)
y = minmax(y, 0, maxy);
else
if(vstyle == FILL_VREFLECT)
y = (y + ay) / cy & 1 ? (ay - y - 1) % cy : (y + ay) % cy;
else
if(vstyle == FILL_VREPEAT)
y = (y + ay) % cy;
return fixed || (x >= 0 && x < cx && y >= 0 && y < cy) ? image[y][x] : RGBAZero();
}
virtual void Get(RGBA *span, int x, int y, unsigned len)
{
interpolator.Begin(x, y, len);
fixed = hstyle && vstyle;
while(len--) {
Point h = interpolator.Get();
// h -= 128;
Point l = h >> 8;
if(hstyle == FILL_HREPEAT)
l.x = (l.x + ax) % cx;
if(vstyle == FILL_VREPEAT)
l.y = (l.y + ay) % cy;
if(fast) {
if(l.x > 0 && l.x < maxx && l.y > 0 && l.y < maxy)
*span = Pixel(l.x, l.y);
else
if(style == 0 && (l.x < -1 || l.x > cx || l.y < -1 || l.y > cy))
*span = RGBAZero();
else
*span = GetPixel(l.x, l.y);
}
else {
RGBAV v;
v.Set(0);
// v.Set(256 * 256 / 2);
h.x &= 255;
h.y &= 255;
Point u = -h + 256;
if(l.x > 0 && l.x < maxx && l.y > 0 && l.y < maxy) {
v.Put(u.x * u.y, Pixel(l.x, l.y));
v.Put(h.x * u.y, Pixel(l.x + 1, l.y));
v.Put(u.x * h.y, Pixel(l.x, l.y + 1));
v.Put(h.x * h.y, Pixel(l.x + 1, l.y + 1));
}
else
if(style == 0 && (l.x < -1 || l.x > cx || l.y < -1 || l.y > cy))
v.Set(0);
else {
v.Put(u.x * u.y, GetPixel(l.x, l.y));
v.Put(h.x * u.y, GetPixel(l.x + 1, l.y));
v.Put(u.x * h.y, GetPixel(l.x, l.y + 1));
v.Put(h.x * h.y, GetPixel(l.x + 1, l.y + 1));
}
span->r = byte(v.r >> 16);
span->g = byte(v.g >> 16);
span->b = byte(v.b >> 16);
span->a = byte(v.a >> 16);
}
++span;
}
}
};
void BufferPainter::RenderImage(double width, const Image& image, const Xform2D& transsrc, dword flags)
{
if(image.GetWidth() == 0 || image.GetHeight() == 0)
return;
PainterImageSpan ss;
ss.style = flags & 15;
ss.hstyle = flags & 3;
ss.vstyle = flags & 12;
ss.fast = flags & FILL_FAST;
ss.Set(transsrc * pathattr.mtx, image);
RenderPath(width, &ss, RGBAZero());
}
void BufferPainter::FillOp(const Image& image, const Xform2D& transsrc, dword flags)
{
Close();
RenderImage(-1, image, transsrc, flags);
}
void BufferPainter::StrokeOp(double width, const Image& image, const Xform2D& transsrc, dword flags)
{
RenderImage(width, image, transsrc, flags);
}
END_UPP_NAMESPACE

View file

@ -1,55 +1,55 @@
#include "Painter.h"
NAMESPACE_UPP
double SquareDist(const Pointf& p1, const Pointf& p2)
{
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}
Pointf Mid(const Pointf& a, const Pointf& b)
{
return (a + b) / 2;
}
Pointf Orthogonal(const Pointf& p)
{
return Pointf(-p.y, p.x);
}
double Squared(const Pointf& p)
{
return p.x * p.x + p.y * p.y;
}
double Length(const Pointf& p)
{
return sqrt(Squared(p));
}
double Bearing(const Pointf& p)
{
return atan2(p.y, p.x);
}
double Distance(const Pointf& p1, const Pointf& p2)
{
return Length(p1 - p2);
}
double SquaredDistance(const Pointf& p1, const Pointf& p2)
{
return Squared(p1 - p2);
}
Pointf Polar(double a)
{
return Pointf(cos(a), sin(a));
}
Pointf Polar(const Pointf& p, double r, double a)
{
return p + r * Polar(a);
}
END_UPP_NAMESPACE
#include "Painter.h"
NAMESPACE_UPP
double SquareDist(const Pointf& p1, const Pointf& p2)
{
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}
Pointf Mid(const Pointf& a, const Pointf& b)
{
return 0.5 * (a + b);
}
Pointf Orthogonal(const Pointf& p)
{
return Pointf(-p.y, p.x);
}
double Squared(const Pointf& p)
{
return p.x * p.x + p.y * p.y;
}
double Length(const Pointf& p)
{
return sqrt(Squared(p));
}
double Bearing(const Pointf& p)
{
return atan2(p.y, p.x);
}
double Distance(const Pointf& p1, const Pointf& p2)
{
return Length(p1 - p2);
}
double SquaredDistance(const Pointf& p1, const Pointf& p2)
{
return Squared(p1 - p2);
}
Pointf Polar(double a)
{
return Pointf(cos(a), sin(a));
}
Pointf Polar(const Pointf& p, double r, double a)
{
return p + r * Polar(a);
}
END_UPP_NAMESPACE

View file

@ -1,130 +1,131 @@
#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)
{
PathAdd<LinearData>(MOVE).p = move = ccontrol = qcontrol = EndPoint(p, rel);
}
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 * 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 * 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) && 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);
}
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

View file

@ -1,352 +1,352 @@
#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::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

View file

@ -1,102 +1,103 @@
#include "Painter.h"
#define LLOG(x) // DLOG(x)
NAMESPACE_UPP
void Rasterizer::CvLine(double x1, double y1, double x2, double y2)
{
LineRaw(Q8(x1), Q8(y1), Q8(x2), Q8(y2));
}
void Rasterizer::LineClip(double x1, double y1, double x2, double y2)
{
if(y1 < cliprect.top) {
if(y2 < cliprect.top)
return;
x1 = (x2 - x1) * (cliprect.top - y1) / (y2 - y1) + x1;
y1 = cliprect.top;
}
else
if(y1 > cliprect.bottom) {
if(y2 > cliprect.bottom)
return;
x1 = (x2 - x1) * (cliprect.bottom - y1) / (y2 - y1) + x1;
y1 = cliprect.bottom;
}
if(y2 < cliprect.top) {
x2 = (x2 - x1) * (cliprect.top - y1) / (y2 - y1) + x1;
y2 = cliprect.top;
}
else
if(y2 > cliprect.bottom) {
x2 = (x2 - x1) * (cliprect.bottom - y1) / (y2 - y1) + x1;
y2 = cliprect.bottom;
}
double y, yy;
if(x1 < cliprect.left) {
if(x2 < cliprect.left) {
CvLine(cliprect.left, y1, cliprect.left, y2);
return;
}
y = (y2 - y1) * (cliprect.left - x1) / (x2 - x1) + y1;
if(x2 > cliprect.right) {
yy = (y2 - y1) * (cliprect.right - x1) / (x2 - x1) + y1;
CvLine(cliprect.left, y1, cliprect.left, y);
CvLine(cliprect.left, y, cliprect.right, yy);
CvLine(cliprect.right, yy, cliprect.right, y2);
return;
}
CvLine(cliprect.left, y1, cliprect.left, y);
CvLine(cliprect.left, y, x2, y2);
return;
}
else
if(x1 > cliprect.right) {
if(x2 > cliprect.right) {
CvLine(cliprect.right, y1, cliprect.right, y2);
return;
}
y = (y2 - y1) * (cliprect.right - x1) / (x2 - x1) + y1;
if(x2 < cliprect.left) {
yy = (y2 - y1) * (cliprect.left - x1) / (x2 - x1) + y1;
CvLine(cliprect.right, y1, cliprect.right, y);
CvLine(cliprect.right, y, cliprect.left, yy);
CvLine(cliprect.left, yy, cliprect.left, y2);
return;
}
CvLine(cliprect.right, y1, cliprect.right, y);
CvLine(cliprect.right, y, x2, y2);
return;
}
if(x2 < cliprect.left) {
y = (y2 - y1) * (cliprect.left - x1) / (x2 - x1) + y1;
CvLine(x1, y1, cliprect.left, y);
CvLine(cliprect.left, y, cliprect.left, y2);
return;
}
else
if(x2 > cliprect.right) {
y = (y2 - y1) * (cliprect.right - x1) / (x2 - x1) + y1;
CvLine(x1, y1, cliprect.right, y);
CvLine(cliprect.right, y, cliprect.right, y2);
return;
}
CvLine(x1, y1, x2, y2);
}
void Rasterizer::Move(const Pointf& p)
{
LLOG("Rasterizer::Move " << p);
p0 = p;
}
void Rasterizer::Line(const Pointf& p)
{
PAINTER_TIMING("Line");
LLOG("Rasterizer::Line " << p);
LineClip(p0.x, p0.y, p.x, p.y);
p0 = p;
}
END_UPP_NAMESPACE
#include "Painter.h"
#define LLOG(x) // DLOG(x)
NAMESPACE_UPP
void Rasterizer::CvLine(double x1, double y1, double x2, double y2)
{
LLOG("CvLine " << x1 << ", " << y1 << " - " << x2 << ", " << y2);
LineRaw(Q8(x1), Q8(y1), Q8(x2), Q8(y2));
}
void Rasterizer::LineClip(double x1, double y1, double x2, double y2)
{
if(y1 < cliprect.top) {
if(y2 < cliprect.top)
return;
x1 = (x2 - x1) * (cliprect.top - y1) / (y2 - y1) + x1;
y1 = cliprect.top;
}
else
if(y1 > cliprect.bottom) {
if(y2 > cliprect.bottom)
return;
x1 = (x2 - x1) * (cliprect.bottom - y1) / (y2 - y1) + x1;
y1 = cliprect.bottom;
}
if(y2 < cliprect.top) {
x2 = (x2 - x1) * (cliprect.top - y1) / (y2 - y1) + x1;
y2 = cliprect.top;
}
else
if(y2 > cliprect.bottom) {
x2 = (x2 - x1) * (cliprect.bottom - y1) / (y2 - y1) + x1;
y2 = cliprect.bottom;
}
double y, yy;
if(x1 < cliprect.left) {
if(x2 < cliprect.left) {
CvLine(cliprect.left, y1, cliprect.left, y2);
return;
}
y = (y2 - y1) * (cliprect.left - x1) / (x2 - x1) + y1;
if(x2 > cliprect.right) {
yy = (y2 - y1) * (cliprect.right - x1) / (x2 - x1) + y1;
CvLine(cliprect.left, y1, cliprect.left, y);
CvLine(cliprect.left, y, cliprect.right, yy);
CvLine(cliprect.right, yy, cliprect.right, y2);
return;
}
CvLine(cliprect.left, y1, cliprect.left, y);
CvLine(cliprect.left, y, x2, y2);
return;
}
else
if(x1 > cliprect.right) {
if(x2 > cliprect.right) {
CvLine(cliprect.right, y1, cliprect.right, y2);
return;
}
y = (y2 - y1) * (cliprect.right - x1) / (x2 - x1) + y1;
if(x2 < cliprect.left) {
yy = (y2 - y1) * (cliprect.left - x1) / (x2 - x1) + y1;
CvLine(cliprect.right, y1, cliprect.right, y);
CvLine(cliprect.right, y, cliprect.left, yy);
CvLine(cliprect.left, yy, cliprect.left, y2);
return;
}
CvLine(cliprect.right, y1, cliprect.right, y);
CvLine(cliprect.right, y, x2, y2);
return;
}
if(x2 < cliprect.left) {
y = (y2 - y1) * (cliprect.left - x1) / (x2 - x1) + y1;
CvLine(x1, y1, cliprect.left, y);
CvLine(cliprect.left, y, cliprect.left, y2);
return;
}
else
if(x2 > cliprect.right) {
y = (y2 - y1) * (cliprect.right - x1) / (x2 - x1) + y1;
CvLine(x1, y1, cliprect.right, y);
CvLine(cliprect.right, y, cliprect.right, y2);
return;
}
CvLine(x1, y1, x2, y2);
}
void Rasterizer::Move(const Pointf& p)
{
LLOG("Rasterizer::Move " << p);
p0 = p;
}
void Rasterizer::Line(const Pointf& p)
{
PAINTER_TIMING("Line");
LLOG("Rasterizer::Line " << p);
LineClip(p0.x, p0.y, p.x, p.y);
p0 = p;
}
END_UPP_NAMESPACE

View file

@ -1,163 +1,163 @@
#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;
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

View file

@ -1,53 +1,53 @@
#include "Painter.h"
NAMESPACE_UPP
void Painter::DoSvgArc(const Pointf& rr, double xangle, int large, int sweep,
const Pointf& p1, const Pointf& p0)
{
Pointf r(fabs(rr.x), fabs(rr.y));
Xform2D m = Xform2D::Rotation(-xangle);
Pointf d1 = m.Transform((p0 - p1) / 2);
Pointf pr = r * r;
Pointf p = d1 * d1;
double check = p.x / pr.x + p.y / pr.y;
if(check > 1)
r *= sqrt(check);
m.x /= r.x;
m.y /= r.y;
Pointf q0 = m.Transform(p0);
Pointf q1 = m.Transform(p1);
double d = SquaredDistance(q0, q1);
double sfactor_sq = 1.0 / d - 0.25;
if(sfactor_sq < 0)
sfactor_sq = 0;
double sfactor = sqrt(sfactor_sq);
if(sweep == large)
sfactor = -sfactor;
Pointf c(0.5 * (q0.x + q1.x) - sfactor * (q1.y - q0.y),
0.5 * (q0.y + q1.y) + sfactor * (q1.x - q0.x));
double theta = Bearing(q0 - c);
double th_sweep = Bearing(q1 - c) - theta;
if(th_sweep < 0 && sweep)
th_sweep += 2 * M_PI;
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));
}
}
END_UPP_NAMESPACE
#include "Painter.h"
NAMESPACE_UPP
void Painter::DoSvgArc(const Pointf& rr, double xangle, int large, int sweep,
const Pointf& p1, const Pointf& p0)
{
Pointf r(fabs(rr.x), fabs(rr.y));
Xform2D m = Xform2D::Rotation(-xangle);
Pointf d1 = m.Transform(Mid(p0, p1));
Pointf pr = r * r;
Pointf p = d1 * d1;
double check = p.x / pr.x + p.y / pr.y;
if(check > 1)
r *= sqrt(check);
m.x /= r.x;
m.y /= r.y;
Pointf q0 = m.Transform(p0);
Pointf q1 = m.Transform(p1);
double d = SquaredDistance(q0, q1);
double sfactor_sq = 1.0 / d - 0.25;
if(sfactor_sq < 0)
sfactor_sq = 0;
double sfactor = sqrt(sfactor_sq);
if(sweep == large)
sfactor = -sfactor;
Pointf c(0.5 * (q0.x + q1.x) - sfactor * (q1.y - q0.y),
0.5 * (q0.y + q1.y) + sfactor * (q1.x - q0.x));
double theta = Bearing(q0 - c);
double th_sweep = Bearing(q1 - c) - theta;
if(th_sweep < 0 && sweep)
th_sweep += 2 * M_PI;
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));
}
}
END_UPP_NAMESPACE

View file

@ -1,115 +1,115 @@
#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 abs(d.x - d.y) < 1e-10 * abs(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;
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