diff --git a/uppsrc/Core/Topt.h b/uppsrc/Core/Topt.h index 85fad3230..6f6f5a502 100644 --- a/uppsrc/Core/Topt.h +++ b/uppsrc/Core/Topt.h @@ -207,67 +207,25 @@ inline void AssertMoveable(T *t = 0) { if(t) AssertMoveable0(t); } #endif -template -inline void Swap_(T& a, T& b) { T tmp = a; a = b; b = tmp; } - -template -inline void MoveableSwap(T& x, T& y) -{ - if(sizeof(T) == 1) - Swap_(*(byte *)&x, *(byte *)&y); - else - if(sizeof(T) == 2) - Swap_(*(uint16 *)&x, *(uint16 *)&y); - else - if(sizeof(T) == 4) - Swap_(*(uint32 *)&x, *(uint32 *)&y); - else - if(sizeof(T) == 8) - Swap_(*(uint64 *)&x, *(uint64 *)&y); - else - if(sizeof(T) == 12) { - Swap_(*(uint64 *)&x, *(uint64 *)&y); - Swap_(*((uint32 *)&x + 2), *((uint32 *)&y + 2)); - } - else - if(sizeof(T) == 16) { - Swap_(*(uint64 *)&x, *(uint64 *)&y); - Swap_(*((uint64 *)&x + 1), *((uint64 *)&y + 1)); - } - else - Swap_(x, y); -} - -template -class MoveableWithSwap : public Moveable { - friend void Swap(T& a, T& b) { MoveableSwap(a, b); } - friend void IterSwap(T *a, T *b) { Swap(*a, *b); } -}; - -#define NTL_MOVEABLE_WITH_SWAP(T) \ - inline void Swap(T& a, T& b) { MoveableSwap(a, b); } \ - inline void IterSwap(T *a, T *b) { MoveableSwap(*a, *b); } \ - NTL_MOVEABLE(T) - -NTL_MOVEABLE_WITH_SWAP(bool); -NTL_MOVEABLE_WITH_SWAP(char); -NTL_MOVEABLE_WITH_SWAP(signed char); -NTL_MOVEABLE_WITH_SWAP(unsigned char); -NTL_MOVEABLE_WITH_SWAP(short); -NTL_MOVEABLE_WITH_SWAP(unsigned short); -NTL_MOVEABLE_WITH_SWAP(int); -NTL_MOVEABLE_WITH_SWAP(unsigned int); -NTL_MOVEABLE_WITH_SWAP(long); -NTL_MOVEABLE_WITH_SWAP(unsigned long); -NTL_MOVEABLE_WITH_SWAP(int64); -NTL_MOVEABLE_WITH_SWAP(uint64); -NTL_MOVEABLE_WITH_SWAP(float); -NTL_MOVEABLE_WITH_SWAP(double); -NTL_MOVEABLE_WITH_SWAP(void *); -NTL_MOVEABLE_WITH_SWAP(const void *); +NTL_MOVEABLE(bool); +NTL_MOVEABLE(char); +NTL_MOVEABLE(signed char); +NTL_MOVEABLE(unsigned char); +NTL_MOVEABLE(short); +NTL_MOVEABLE(unsigned short); +NTL_MOVEABLE(int); +NTL_MOVEABLE(unsigned int); +NTL_MOVEABLE(long); +NTL_MOVEABLE(unsigned long); +NTL_MOVEABLE(int64); +NTL_MOVEABLE(uint64); +NTL_MOVEABLE(float); +NTL_MOVEABLE(double); +NTL_MOVEABLE(void *); +NTL_MOVEABLE(const void *); #if defined(_NATIVE_WCHAR_T_DEFINED) || defined(COMPILER_GCC) -NTL_MOVEABLE_WITH_SWAP(wchar_t); +NTL_MOVEABLE(wchar_t); #endif template diff --git a/uppsrc/Painter/Approximate.cpp b/uppsrc/Painter/Approximate.cpp index f7c90a435..19aef6fcc 100644 --- a/uppsrc/Painter/Approximate.cpp +++ b/uppsrc/Painter/Approximate.cpp @@ -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 diff --git a/uppsrc/Painter/BufferPainter.h b/uppsrc/Painter/BufferPainter.h index ff6d7bc49..c02b67643 100644 --- a/uppsrc/Painter/BufferPainter.h +++ b/uppsrc/Painter/BufferPainter.h @@ -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 *pattern; - int patterni; - double sum, rem; - bool flag; - Pointf p0; - - void Put(const Pointf& p); - -public: - void Init(const Vector& 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 { - int16 x; - int16 cover; - int area; - - bool operator<(const Cell& b) const { return x < b.x; } - }; - - Rectf cliprect; - Pointf p0; - Buffer< Vector > 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& 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 type; - Vector data; - }; - struct Attr : Moveable { - Xform2D mtx; - double tolerance; - bool evenodd; - byte join; - byte cap; - double miter_limit; - WithDeepCopy< Vector > dash; - WithDeepCopy< Vector > stop; - WithDeepCopy< Vector > stop_color; - double dash_start; - double opacity; - int cliplevel; - bool hasclip; - bool mask; - bool noaa; - }; - - ImageBuffer& ib; - - Attr attr; - Attr pathattr; - Array attrstack; - Vector< Buffer > clip; - Array< ImageBuffer > mask; - - - Image gradient; - RGBA gradient1, gradient2; - int gradientn; - - Path path; - Pointf current, ccontrol, qcontrol, move; - Rectf pathrect; - - Rasterizer rasterizer; - Buffer span; - - void *PathAddRaw(int type, int size); - template 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 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 *pattern; + int patterni; + double sum, rem; + bool flag; + Pointf p0; + + void Put(const Pointf& p); + +public: + void Init(const Vector& 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 { + int16 x; + int16 cover; + int area; + + bool operator<(const Cell& b) const { return x < b.x; } + }; + + Rectf cliprect; + Pointf p0; + Buffer< Vector > 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& 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 type; + Vector data; + }; + struct Attr : Moveable { + Xform2D mtx; + double tolerance; + bool evenodd; + byte join; + byte cap; + double miter_limit; + WithDeepCopy< Vector > dash; + WithDeepCopy< Vector > stop; + WithDeepCopy< Vector > stop_color; + double dash_start; + double opacity; + int cliplevel; + bool hasclip; + bool mask; + bool noaa; + }; + + ImageBuffer& ib; + + Attr attr; + Attr pathattr; + Array attrstack; + Vector< Buffer > clip; + Array< ImageBuffer > mask; + + + Image gradient; + RGBA gradient1, gradient2; + int gradientn; + + Path path; + Pointf current, ccontrol, qcontrol, move; + Rectf pathrect; + + Rasterizer rasterizer; + Buffer span; + + void *PathAddRaw(int type, int size); + template 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 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); +}; diff --git a/uppsrc/Painter/Fillers.cpp b/uppsrc/Painter/Fillers.cpp index e2c73ac2e..fe548224f 100644 --- a/uppsrc/Painter/Fillers.cpp +++ b/uppsrc/Painter/Fillers.cpp @@ -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 diff --git a/uppsrc/Painter/Gradient.cpp b/uppsrc/Painter/Gradient.cpp index e0c922b91..bbe4c5c09 100644 --- a/uppsrc/Painter/Gradient.cpp +++ b/uppsrc/Painter/Gradient.cpp @@ -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 diff --git a/uppsrc/Painter/Image.cpp b/uppsrc/Painter/Image.cpp index 34f9820d3..7dac64cd9 100644 --- a/uppsrc/Painter/Image.cpp +++ b/uppsrc/Painter/Image.cpp @@ -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 diff --git a/uppsrc/Painter/Math.cpp b/uppsrc/Painter/Math.cpp index 5d3c40903..147b2edaa 100644 --- a/uppsrc/Painter/Math.cpp +++ b/uppsrc/Painter/Math.cpp @@ -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 diff --git a/uppsrc/Painter/Path.cpp b/uppsrc/Painter/Path.cpp index 323816277..599df59df 100644 --- a/uppsrc/Painter/Path.cpp +++ b/uppsrc/Painter/Path.cpp @@ -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(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(LINE).p = ccontrol = qcontrol = EndPoint(p, rel); -} - -void BufferPainter::QuadraticOp(const Pointf& p1, const Pointf& p, bool rel) -{ - DoMove0(); - QuadraticData& m = PathAdd(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(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(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(MOVE).p = move; +} + +void BufferPainter::DoMove0() +{ + if(IsNull(move)) + MoveOp(Pointf(0, 0), false); +} + +void BufferPainter::LineOp(const Pointf& p, bool rel) +{ + DoMove0(); + PathAdd(LINE).p = ccontrol = qcontrol = EndPoint(p, rel); +} + +void BufferPainter::QuadraticOp(const Pointf& p1, const Pointf& p, bool rel) +{ + DoMove0(); + QuadraticData& m = PathAdd(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(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(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 diff --git a/uppsrc/Painter/Rasterizer.cpp b/uppsrc/Painter/Rasterizer.cpp index 343677fee..8763eda70 100644 --- a/uppsrc/Painter/Rasterizer.cpp +++ b/uppsrc/Painter/Rasterizer.cpp @@ -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& 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& 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& 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& 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 diff --git a/uppsrc/Painter/RasterizerClip.cpp b/uppsrc/Painter/RasterizerClip.cpp index 1578ea9a9..90a4115d4 100644 --- a/uppsrc/Painter/RasterizerClip.cpp +++ b/uppsrc/Painter/RasterizerClip.cpp @@ -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 diff --git a/uppsrc/Painter/Render.cpp b/uppsrc/Painter/Render.cpp index be638d674..882f41d71 100644 --- a/uppsrc/Painter/Render.cpp +++ b/uppsrc/Painter/Render.cpp @@ -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 BufferPainter::RenderPath(double width, SpanSource *ss, const RGBA& color) -{ - Buffer 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 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 BufferPainter::RenderPath(double width, SpanSource *ss, const RGBA& color) +{ + Buffer 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 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 diff --git a/uppsrc/Painter/SvgArc.cpp b/uppsrc/Painter/SvgArc.cpp index 220b2a8eb..f21f36aa2 100644 --- a/uppsrc/Painter/SvgArc.cpp +++ b/uppsrc/Painter/SvgArc.cpp @@ -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 diff --git a/uppsrc/Painter/Xform2D.cpp b/uppsrc/Painter/Xform2D.cpp index bc19b470b..18fbf769c 100644 --- a/uppsrc/Painter/Xform2D.cpp +++ b/uppsrc/Painter/Xform2D.cpp @@ -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