diff --git a/uppdev/Painter/BufferPainter.h b/uppdev/Painter/BufferPainter.h index 2e9d1bfbe..b3778ce91 100644 --- a/uppdev/Painter/BufferPainter.h +++ b/uppdev/Painter/BufferPainter.h @@ -55,7 +55,7 @@ private: const Pointf& a0, const Pointf& b0); public: - Stroker(double width, double miterlimit, double tolerance, int linecap, int linejoin); + void Init(double width, double miterlimit, double tolerance, int linecap, int linejoin); }; class Dasher : public LinearPathFilter { @@ -64,7 +64,7 @@ public: virtual void Line(const Pointf& p); private: - const Vector& pattern; + const Vector *pattern; int patterni; double sum, rem; bool flag; @@ -73,7 +73,7 @@ private: void Put(const Pointf& p); public: - Dasher(const Vector& pattern, double distance); + void Init(const Vector& pattern, double distance); }; struct Transformer : public LinearPathFilter { @@ -117,6 +117,11 @@ inline void AlphaBlendCover8(RGBA& t, const RGBA& c, int cover) 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); @@ -134,7 +139,6 @@ private: Rectf cliprect; Pointf p0; Buffer< Vector > cell; - int xmax, ymax; int min_y; int max_y; Size sz; @@ -180,10 +184,31 @@ struct ScanLine { }; struct SpanSource { - virtual void Get(RGBA *_span, int x, int y, unsigned len); + virtual void Get(RGBA *span, int x, int y, unsigned len) = 0; }; void Render(ImageBuffer& ib, Rasterizer& r, const RGBA& color, bool evenodd); +void Render(ImageBuffer& ib, Rasterizer& r, SpanSource *s, RGBA *buffer, int opacity8, bool evenodd); + +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 Begin(int x, int y, int len); + void Get(int& x, int& y); + void Set(const Xform2D& m) { xform = m; } +}; class BufferPainter : public Painter { protected: @@ -198,8 +223,23 @@ protected: virtual void CloseOp(); 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 ColorStopOp(double pos, const RGBA& color); virtual void ClearStopsOp(); @@ -267,16 +307,21 @@ public: Rectf pathrect; Rasterizer rasterizer; + Buffer span; void *PathAddRaw(int type, int size); template T& PathAdd(int type) { return *(T *)PathAddRaw(type, sizeof(T)); } - void DoMove0(); - void ClearPath(); - void RenderPath(LinearPathFilter *first_filter, LinearPathFilter *last_filter, - const RGBA& color, bool evenodd); Pointf PathPoint(const Pointf& p, bool rel); Pointf EndPoint(const Pointf& p, bool rel); + void DoMove0(); + void ClearPath(); + void 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 *t, RGBA color1, RGBA color2, int cx); + Image GetGradient(const RGBA& color1, const RGBA& color2, const Pointf& p1, const Pointf& p2); void ColorStop0(Attr& a, double pos, const RGBA& color); public: diff --git a/uppdev/Painter/Dasher.cpp b/uppdev/Painter/Dasher.cpp index a7d834b57..0fd7997ed 100644 --- a/uppdev/Painter/Dasher.cpp +++ b/uppdev/Painter/Dasher.cpp @@ -29,26 +29,26 @@ void Dasher::Line(const Pointf& p) pos += rem; Put(pos / len * v + p0); flag = !flag; - rem = pattern[patterni]; - patterni = (patterni + 1) % pattern.GetCount(); + rem = (*pattern)[patterni]; + patterni = (patterni + 1) % pattern->GetCount(); } rem -= len - pos; Put(p); p0 = p; } -Dasher::Dasher(const Vector& p, double distance) -: pattern(p) +void Dasher::Init(const Vector& p, double distance) { - sum = Sum0(pattern); + pattern = &p; + sum = Sum0(p); if(sum == 0) return; distance -= int(distance / sum) * sum; patterni = 0; flag = false; for(;;) { - rem = pattern[patterni]; - patterni = (patterni + 1) % pattern.GetCount(); + rem = (*pattern)[patterni]; + patterni = (patterni + 1) % pattern->GetCount(); flag = !flag; if(rem > distance) { rem -= distance; diff --git a/uppdev/Painter/FontWin32.cpp b/uppdev/Painter/FontWin32.cpp new file mode 100644 index 000000000..ef212462c --- /dev/null +++ b/uppdev/Painter/FontWin32.cpp @@ -0,0 +1,114 @@ +//---------------------------------------------------------------------------- +// 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 coM_PIes. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +//---------------------------------------------------------------------------- +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://www.antigrain.com +//---------------------------------------------------------------------------- + +// Recycled for U++ by Miroslav Fidler 2008 + +#include "Painter.h" + +NAMESPACE_UPP + +#ifdef PLATFORM_WIN32 + +inline double fx_to_dbl(const FIXED& p) { + return double(p.value) + double(p.fract) * (1.0 / 65536.0); +} + +void RenderCharPath(const char* gbuf, unsigned total_size, Painter& sw, double xx, double yy) +{ + const char* cur_glyph = gbuf; + const char* end_glyph = gbuf + total_size; + + while(cur_glyph < end_glyph) { + const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph; + const char* end_poly = cur_glyph + th->cb; + const char* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER); + sw.Move(xx + fx_to_dbl(th->pfxStart.x), yy - fx_to_dbl(th->pfxStart.y)); + while(cur_poly < end_poly) { + const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly; + if (pc->wType == TT_PRIM_LINE) + for(int i = 0; i < pc->cpfx; i++) + sw.Line(xx + fx_to_dbl(pc->apfx[i].x), yy - fx_to_dbl(pc->apfx[i].y)); + if (pc->wType == TT_PRIM_QSPLINE) { + int u; + for (u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline + POINTFX pnt_b = pc->apfx[u]; // B is always the current point + POINTFX pnt_c = pc->apfx[u+1]; + if (u < pc->cpfx - 2) { // If not on last spline, compute C + *(int*)&pnt_c.x = (*(int*)&pnt_b.x + *(int*)&pnt_c.x) / 2; + *(int*)&pnt_c.y = (*(int*)&pnt_b.y + *(int*)&pnt_c.y) / 2; + } + sw.Quadratic(xx + fx_to_dbl(pnt_b.x), yy - fx_to_dbl(pnt_b.y), + xx + fx_to_dbl(pnt_c.x), yy - fx_to_dbl(pnt_c.y)); + } + } + cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx; + } + sw.Close(); + cur_glyph += th->cb; + } +} + +struct FontChar { + Font fnt; + int chr; + + bool operator==(const FontChar& b) const { return fnt == b.fnt && chr == b.chr; } + unsigned GetHashValue() const { return CombineHash(fnt, chr); } +}; + +struct sMakeCharOutline : LRUCache::Maker { + FontChar fc; + + FontChar Key() const { return fc; } + int Make(String& s) const { + static ScreenDraw w; + w.SetFont(fc.fnt); + GLYPHMETRICS gm; + MAT2 m_matrix; + memset(&m_matrix, 0, sizeof(m_matrix)); + m_matrix.eM11.value = 1; + m_matrix.eM22.value = 1; + s.Clear(); + int gsz = GetGlyphOutlineW(w.GetHandle(), fc.chr, GGO_NATIVE, &gm, 0, NULL, &m_matrix); + if(gsz < 0) + return 0; + StringBuffer gb(gsz); + gsz = GetGlyphOutlineW(w.GetHandle(), fc.chr, GGO_NATIVE, &gm, gsz, ~gb, &m_matrix); + if(gsz < 0) + return 0; + s = gb; + return gsz; + } +}; + +void Painter::CharacterOp(double x, double y, int ch, Font fnt) +{ + PAINTER_TIMING("CharacterOp"); + String s; + INTERLOCKED { + static LRUCache cache; + cache.Shrink(100000); + sMakeCharOutline h; + h.fc.fnt = fnt; + h.fc.chr = ch; + s = cache.Get(h); + } + RenderCharPath(s, s.GetLength(), *this, x, y + fnt.Info().GetAscent()); + EvenOdd(true); +} + +#endif + +END_UPP_NAMESPACE diff --git a/uppdev/Painter/FontX11.cpp b/uppdev/Painter/FontX11.cpp new file mode 100644 index 000000000..827722fbf --- /dev/null +++ b/uppdev/Painter/FontX11.cpp @@ -0,0 +1,152 @@ +//---------------------------------------------------------------------------- +// 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 coM_PIes. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +//---------------------------------------------------------------------------- +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://www.antigrain.com +//---------------------------------------------------------------------------- + +// Recycled for U++ by Miroslav Fidler 2008 + +#include "Painter.h" + +NAMESPACE_UPP + +#ifdef PLATFORM_X11 + +static inline double ft_dbl(int p) +{ + return double(p) / 64.0; +} + +bool RenderOutline(const FT_Outline& outline, Painter& path, double xx, double yy) +{ + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + double x1, y1, x2, y2, x3, y3; + FT_Vector* point; + FT_Vector* limit; + char* tags; + int n; // index of contour in outline + char tag; // current point's state + int first = 0; // index of first point in contour + for(n = 0; n < outline.n_contours; n++) { + int last = outline.contours[n]; + limit = outline.points + last; + v_start = outline.points[first]; + v_last = outline.points[last]; + v_control = v_start; + point = outline.points + first; + tags = outline.tags + first; + tag = FT_CURVE_TAG(tags[0]); + if(tag == FT_CURVE_TAG_CUBIC) return false; + if(tag == FT_CURVE_TAG_CONIC) { + if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON) { + // start at last point if it is on the curve + v_start = v_last; + limit--; + } + else { + // if both first and last points are conic, + // start at their middle and record its position + // for closure + v_start.x = (v_start.x + v_last.x) / 2; + v_start.y = (v_start.y + v_last.y) / 2; + v_last = v_start; + } + point--; + tags--; + } + path.Move(ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy); + while(point < limit) { + point++; + tags++; + + tag = FT_CURVE_TAG(tags[0]); + switch(tag) { + case FT_CURVE_TAG_ON: + path.Line(ft_dbl(point->x) + xx, -ft_dbl(point->y) + yy); + continue; + case FT_CURVE_TAG_CONIC: + v_control.x = point->x; + v_control.y = point->y; + Do_Conic: + if(point < limit) { + FT_Vector vec; + FT_Vector v_middle; + point++; + tags++; + tag = FT_CURVE_TAG(tags[0]); + vec.x = point->x; + vec.y = point->y; + if(tag == FT_CURVE_TAG_ON) { + path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy, + ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy); + continue; + } + if(tag != FT_CURVE_TAG_CONIC) return false; + v_middle.x = (v_control.x + vec.x) / 2; + v_middle.y = (v_control.y + vec.y) / 2; + path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy, + ft_dbl(v_middle.x) + xx, -ft_dbl(v_middle.y) + yy); + v_control = vec; + goto Do_Conic; + } + path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy, + ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy); + goto Close; + + default: + FT_Vector vec1, vec2; + if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC) + return false; + vec1.x = point[0].x; + vec1.y = point[0].y; + vec2.x = point[1].x; + vec2.y = point[1].y; + point += 2; + tags += 2; + if(point <= limit) { + FT_Vector vec; + vec.x = point->x; + vec.y = point->y; + path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy, + ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy, + ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy); + continue; + } + path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy, + ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy, + ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy); + goto Close; + } + } + Close: + path.Close(); + first = last + 1; + } + return true; +} + +void Painter::CharacterOp(double x, double y, int ch, Font fnt) +{ + PAINTER_TIMING("CharacterOp"); + FontInfo fi = fnt.Info(); + FT_Face face = XftLockFace(fi.GetXftFont()); + int glyph_index = FT_Get_Char_Index(face, ch); + if(FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0) + RenderOutline(face->glyph->outline, *this, x, y + fnt.Info().GetAscent()); + XftUnlockFace(fi.GetXftFont()); +} + +#endif + +END_UPP_NAMESPACE diff --git a/uppdev/Painter/Gradient.cpp b/uppdev/Painter/Gradient.cpp new file mode 100644 index 000000000..b7cab7c35 --- /dev/null +++ b/uppdev/Painter/Gradient.cpp @@ -0,0 +1,58 @@ +#include "Painter.h" + +NAMESPACE_UPP + +void BufferPainter::MakeGradient(RGBA *t, RGBA color1, RGBA color2, int cx) +{ + 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] * (cx - 1)); + ch = pathattr.stop_color[i]; + } + else { + h = cx - 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; +} + +Image BufferPainter::GetGradient(const RGBA& color1, const RGBA& color2, const Pointf& p1, const Pointf& p2) +{ + int n = minmax(int(Distance(p1, p2) * pathattr.mtx.GetScale()), 2, 4096); + ImageBuffer ib(n, 1); + MakeGradient(ib, color1, color2, n); + return ib; +} + +void BufferPainter::FillOp(const Pointf& p1, const RGBA& color1, const Pointf& p2, const RGBA& color2, int style) +{ + Fill(GetGradient(color1, color2, p1, p2), p1.x, p1.y, p2.x, p2.y, + 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) +{ + Stroke(width, GetGradient(color1, color2, p1, p2), p1.x, p1.y, p2.x, p2.y, + FILL_VPAD | FILL_FAST | + (style == GRADIENT_PAD ? FILL_HPAD : style == GRADIENT_REPEAT + ? FILL_HREPEAT : FILL_HREFLECT)); +} + +END_UPP_NAMESPACE diff --git a/uppdev/Painter/Image.cpp b/uppdev/Painter/Image.cpp new file mode 100644 index 000000000..316f596d9 --- /dev/null +++ b/uppdev/Painter/Image.cpp @@ -0,0 +1,240 @@ +#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; + ay = 6000000 / cy * cy; + } + + 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--) { + int x_hr; + int y_hr; + interpolator.Get(x_hr, y_hr); + x_hr -= 128; + y_hr -= 128; + int x_lr = x_hr >> 8; + int y_lr = y_hr >> 8; + if(hstyle == FILL_HREPEAT) + x_lr = (x_lr + ax) % cx; + if(vstyle == FILL_VREPEAT) + y_lr = (y_lr + ay) % cy; + if(fast) { + if(x_lr > 0 && x_lr < maxx && y_lr > 0 && y_lr < maxy) + *span = Pixel(x_lr, y_lr); + else + if(style == 0 && (x_lr < -1 || x_lr > cx || y_lr < -1 || y_lr > cy)) + *span = RGBAZero(); + else + *span = GetPixel(x_lr, y_lr); + } + else { + RGBAV v; + v.Set(256 * 256 / 2); + x_hr &= 255; + y_hr &= 255; + if(x_lr > 0 && x_lr < maxx && y_lr > 0 && y_lr < maxy) { + v.Put((256 - x_hr) * (256 - y_hr), Pixel(x_lr, y_lr)); + v.Put(x_hr * (256 - y_hr), Pixel(x_lr + 1, y_lr)); + v.Put((256 - x_hr) * y_hr, Pixel(x_lr, y_lr + 1)); + v.Put(x_hr * y_hr, Pixel(x_lr + 1, y_lr + 1)); + } + else + if(style == 0 && (x_lr < -1 || x_lr > cx || y_lr < -1 || y_lr > cy)) + v.Set(0); + else { + v.Put((256 - x_hr) * (256 - y_hr), GetPixel(x_lr, y_lr)); + v.Put(x_hr * (256 - y_hr), GetPixel(x_lr + 1, y_lr)); + v.Put((256 - x_hr) * y_hr, GetPixel(x_lr, y_lr + 1)); + v.Put(x_hr * y_hr, GetPixel(x_lr + 1, y_lr + 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 diff --git a/uppdev/Painter/Interpolator.cpp b/uppdev/Painter/Interpolator.cpp new file mode 100644 index 000000000..161963b4f --- /dev/null +++ b/uppdev/Painter/Interpolator.cpp @@ -0,0 +1,46 @@ +#include "Painter.h" + +NAMESPACE_UPP + +void LinearInterpolator::Dda2::Set(int p1, int p2, int len) +{ + count = len <= 0 ? 1 : len; + lift = (p2 - p1) / count; + rem = (p2 - p1) % count; + mod = rem; + p = p1; + if(mod <= 0) { + mod += count; + rem += count; + lift--; + } + mod -= count; +} + +int LinearInterpolator::Dda2::Get() +{ + int pp = p; + mod += rem; + p += lift; + if(mod > 0) { + mod -= count; + p++; + } + return pp; +} + +void LinearInterpolator::Begin(int x, int y, int len) +{ + Pointf p1 = xform.Transform(Pointf(x, y) + 0.5); + Pointf p2 = xform.Transform(Pointf(x + len, y) + 0.5); + ddax.Set(Q8(p1.x), Q8(p2.x), len); + dday.Set(Q8(p1.y), Q8(p2.y), len); +} + +void LinearInterpolator::Get(int& x, int& y) +{ + x = ddax.Get(); + y = dday.Get(); +} + +END_UPP_NAMESPACE diff --git a/uppdev/Painter/Painter.cpp b/uppdev/Painter/Painter.cpp index e527c25d7..aac4fd213 100644 --- a/uppdev/Painter/Painter.cpp +++ b/uppdev/Painter/Painter.cpp @@ -182,12 +182,81 @@ Painter& Painter::RelCubic(double x2, double y2, double x, double y) return *this; } +Xform2D GetLineSzXform(const Pointf& p1, const Pointf& p2, const Sizef& sz) +{ + Xform2D m = Xform2D::Scale(Distance(p1, p2) / sz.cx); + m = m * Xform2D::Rotation(Bearing(p2 - p1)); + m = m * Xform2D::Translation(p1.x, p1.y); + return m; +} + +Painter& Painter::Fill(const Image& image, Pointf p1, Pointf p2, dword flags) +{ + return Fill(image, GetLineSzXform(p1, p2, image.GetSize()), flags); +} + +Painter& Painter::Fill(const Image& image, double x1, double y1, + double x2, double y2, dword flags) +{ + return Fill(image, Pointf(x1, y1), Pointf(x2, y2), flags); +} + +Painter& Painter::Fill(double x1, double y1, const RGBA& color1, double x2, double y2, const RGBA& color2, int style) +{ + return Fill(Pointf(x1, y1), color1, Pointf(x2, y2), color2, style); +} + +Painter& Painter::Fill(double fx, double fy, const RGBA& color1, double cx, double cy, double r, const RGBA& color2, int style) +{ + return Fill(Pointf(fx, fy), color1, Pointf(cx, cy), r, color2, style); +} + +Painter& Painter::Fill(const Pointf& c, const RGBA& color1, double r, const RGBA& color2, int style) +{ + return Fill(c, color1, c, r, color2, style); +} + +Painter& Painter::Fill(double x, double y, const RGBA& color1, double r, const RGBA& color2, int style) +{ + return Fill(Pointf(x, y), color1, r, color2, style); +} + Painter& Painter::Translate(double x, double y) { Transform(Xform2D::Translation(x, y)); return *this; } +Painter& Painter::Stroke(double width, const Image& image, const Pointf& p1, const Pointf& p2, dword flags) +{ + return Stroke(width, image, GetLineSzXform(p1, p2, image.GetSize()), flags); +} + +Painter& Painter::Stroke(double width, const Image& image, double x1, double y1, double x2, double y2, dword flags) +{ + return Stroke(width, image, Pointf(x1, y1), Pointf(x2, y2), flags); +} + +Painter& Painter::Stroke(double width, double x1, double y1, const RGBA& color1, double x2, double y2, const RGBA& color2, int style) +{ + return Stroke(width, Pointf(x1, y1), color1, Pointf(x2, y2), color2, style); +} + +Painter& Painter::Stroke(double width, double fx, double fy, const RGBA& color1, double cx, double cy, double r, const RGBA& color2, int style) +{ + return Stroke(width, Pointf(fx, fy), color1, Pointf(cx, cy), r, color2, style); +} + +Painter& Painter::Stroke(double width, const Pointf& c, const RGBA& color1, double r, const RGBA& color2, int style) +{ + return Stroke(width, c, color1, c, r, color2, style); +} + +Painter& Painter::Stroke(double width, double x, double y, const RGBA& color1, double r, const RGBA& color2, int style) +{ + return Stroke(width, Pointf(x, y), color1, r, color2, style); +} + Painter& Painter::Rotate(double a) { Transform(Xform2D::Rotation(a)); @@ -222,4 +291,14 @@ Painter& Painter::Dash(const char *dash, double start) return *this; } +Painter& Painter::Rectangle(double x, double y, double cx, double cy) +{ + Move(x, y); + Line(x + cx, y); + Line(x + cx, y + cy); + Line(x, y + cy); + Close(); + return *this; +} + END_UPP_NAMESPACE diff --git a/uppdev/Painter/Painter.h b/uppdev/Painter/Painter.h index 47bfb25b1..e4a8ef249 100644 --- a/uppdev/Painter/Painter.h +++ b/uppdev/Painter/Painter.h @@ -21,6 +21,8 @@ struct Xform2D { static Xform2D Scale(double scale); static Xform2D Rotation(double fi); static Xform2D Sheer(double fi); + + Xform2D(); }; Xform2D operator*(const Xform2D& a, const Xform2D& b); @@ -69,8 +71,26 @@ protected: virtual void CloseOp() = 0; virtual void FillOp(const RGBA& color) = 0; + virtual void FillOp(const Image& image, const Xform2D& transsrc, dword flags) = 0; + virtual void FillOp(const Pointf& p1, const RGBA& color1, + const Pointf& p2, const RGBA& color2, + int style) = 0; + virtual void FillOp(const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, + int style) = 0; virtual void StrokeOp(double width, const RGBA& rgba) = 0; + virtual void StrokeOp(double width, const Image& image, const Xform2D& transsrc, + dword flags) = 0; + virtual void StrokeOp(double width, const Pointf& p1, const RGBA& color1, + const Pointf& p2, const RGBA& color2, + int style) = 0; + virtual void StrokeOp(double width, const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, + int style) = 0; + + virtual void CharacterOp(double x, double y, int ch, Font fnt); + virtual void TextOp(double x, double y, const wchar *text, Font fnt, int n = -1, double *dx = NULL); virtual void ColorStopOp(double pos, const RGBA& color) = 0; virtual void ClearStopsOp() = 0; @@ -142,8 +162,47 @@ public: Painter& Path(const char *path); Painter& Fill(const RGBA& color); + Painter& Fill(const Image& image, const Xform2D& transsrc = Xform2D::Identity(), dword flags = 0); + Painter& Fill(const Image& image, Pointf p1, Pointf p2, dword flags = 0); + Painter& Fill(const Image& image, double x1, double y1, double x2, double y2, + dword flags = 0); + Painter& Fill(const Pointf& p1, const RGBA& color1, + const Pointf& p2, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Fill(double x1, double y1, const RGBA& color1, + double x2, double y2, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Fill(const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Fill(double fx, double fy, const RGBA& color1, + double cx, double cy, double r, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Fill(const Pointf& c, const RGBA& color1, + double r, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Fill(double x, double y, const RGBA& color1, + double r, const RGBA& color2, int style = GRADIENT_PAD); Painter& Stroke(double width, const RGBA& color); + Painter& Stroke(double width, const Image& image, const Xform2D& transsrc, dword flags = 0); + Painter& Stroke(double width, const Image& image, const Pointf& p1, const Pointf& p2, + dword flags = 0); + Painter& Stroke(double width, const Image& image, double x1, double y1, double x2, double y2, + dword flags = 0); + Painter& Stroke(double width, const Pointf& p1, const RGBA& color1, + const Pointf& p2, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Stroke(double width, double x1, double y1, const RGBA& color1, + double x2, double y2, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Stroke(double width, const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Stroke(double width, double fx, double fy, const RGBA& color1, + double cx, double cy, double r, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Stroke(double width, const Pointf& c, const RGBA& color1, + double r, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Stroke(double width, double x, double y, const RGBA& color1, + double r, const RGBA& color2, int style = GRADIENT_PAD); + + Painter& Character(double x, double y, int ch, Font fnt); + Painter& Text(double x, double y, const wchar *text, Font fnt, int n = -1, double *dx = NULL); + Painter& Text(double x, double y, const WString& s, Font fnt, double *dx = NULL); + Painter& Text(double x, double y, const String& s, Font fnt, double *dx = NULL); + Painter& Text(double x, double y, const char *text, Font fnt, int n = -1, double *dx = NULL); void Begin(); void End(); @@ -164,6 +223,8 @@ public: Painter& Rotate(double a); Painter& Scale(double scalex, double scaley); Painter& Scale(double scale); + + Painter& Rectangle(double x, double y, double cx, double cy); }; #include "Painter.hpp" diff --git a/uppdev/Painter/Painter.hpp b/uppdev/Painter/Painter.hpp index bc2bbaf3b..2098d1133 100644 --- a/uppdev/Painter/Painter.hpp +++ b/uppdev/Painter/Painter.hpp @@ -60,6 +60,27 @@ Painter& Painter::Fill(const RGBA& color) return *this; } +inline +Painter& Painter::Fill(const Image& image, const Xform2D& transsrc, dword flags) +{ + FillOp(image, transsrc, flags); + return *this; +} + +inline +Painter& Painter::Fill(const Pointf& p1, const RGBA& color1, const Pointf& p2, const RGBA& color2, int style) +{ + FillOp(p1, color1, p2, color2, style); + return *this; +} + +inline +Painter& Painter::Fill(const Pointf& f, const RGBA& color1, const Pointf& c, double r, const RGBA& color2, int style) +{ + FillOp(f, color1, c, r, color2, style); + return *this; +} + inline Painter& Painter::Stroke(double width, const RGBA& color) { @@ -67,6 +88,27 @@ Painter& Painter::Stroke(double width, const RGBA& color) return *this; } +inline +Painter& Painter::Stroke(double width, const Image& image, const Xform2D& transsrc, dword flags) +{ + StrokeOp(width, image, transsrc, flags); + return *this; +} + +inline +Painter& Painter::Stroke(double width, const Pointf& p1, const RGBA& color1, const Pointf& p2, const RGBA& color2, int style) +{ + StrokeOp(width, p1, color1, p2, color2, style); + return *this; +} + +inline +Painter& Painter::Stroke(double width, const Pointf& f, const RGBA& color1, const Pointf& c, double r, const RGBA& color2, int style) +{ + StrokeOp(width, f, color1, c, r, color2, style); + return *this; +} + inline Painter& Painter::ColorStop(double pos, const RGBA& color) { ColorStopOp(pos, color); diff --git a/uppdev/Painter/Painter.upp b/uppdev/Painter/Painter.upp index 7ecc4b916..b836df173 100644 --- a/uppdev/Painter/Painter.upp +++ b/uppdev/Painter/Painter.upp @@ -1,5 +1,3 @@ -optimize_speed; - uses Core, CtrlLib; @@ -9,6 +7,9 @@ file Painter.hpp, Painter.cpp, PainterPath.cpp, + FontWin32.cpp, + FontX11.cpp, + Text.cpp, BufferPainter.h, Math.cpp, Xform2D.cpp, @@ -16,14 +17,18 @@ file Stroker.cpp, Dasher.cpp, Transformer.cpp, - Rasterizer.cpp, - RasterizerClip.cpp, + Interpolator.cpp optimize_speed, + Rasterizer.cpp optimize_speed, + RasterizerClip.cpp optimize_speed, ScanLineFiller.cpp, - SolidFiller.cpp, + SolidFiller.cpp optimize_speed, SolidFillerMask.cpp, - Path.cpp, + Path.cpp optimize_speed, Context.cpp, - Render.cpp; + Render.cpp optimize_speed, + Image.cpp optimize_speed, + Gradient.cpp optimize_speed, + RadialGradient.cpp optimize_speed; mainconfig "" = "GUI"; diff --git a/uppdev/Painter/RadialGradient.cpp b/uppdev/Painter/RadialGradient.cpp new file mode 100644 index 000000000..003899d49 --- /dev/null +++ b/uppdev/Painter/RadialGradient.cpp @@ -0,0 +1,219 @@ +#include "Painter.h" + +NAMESPACE_UPP + +uint16 g_sqrt_table[1024] = +{ + 0, + 2048,2896,3547,4096,4579,5017,5418,5793,6144,6476,6792,7094,7384,7663,7932,8192,8444, + 8689,8927,9159,9385,9606,9822,10033,10240,10443,10642,10837,11029,11217,11403,11585, + 11765,11942,12116,12288,12457,12625,12790,12953,13114,13273,13430,13585,13738,13890, + 14040,14189,14336,14482,14626,14768,14910,15050,15188,15326,15462,15597,15731,15864, + 15995,16126,16255,16384,16512,16638,16764,16888,17012,17135,17257,17378,17498,17618, + 17736,17854,17971,18087,18203,18318,18432,18545,18658,18770,18882,18992,19102,19212, + 19321,19429,19537,19644,19750,19856,19961,20066,20170,20274,20377,20480,20582,20684, + 20785,20886,20986,21085,21185,21283,21382,21480,21577,21674,21771,21867,21962,22058, + 22153,22247,22341,22435,22528,22621,22713,22806,22897,22989,23080,23170,23261,23351, + 23440,23530,23619,23707,23796,23884,23971,24059,24146,24232,24319,24405,24491,24576, + 24661,24746,24831,24915,24999,25083,25166,25249,25332,25415,25497,25580,25661,25743, + 25824,25905,25986,26067,26147,26227,26307,26387,26466,26545,26624,26703,26781,26859, + 26937,27015,27092,27170,27247,27324,27400,27477,27553,27629,27705,27780,27856,27931, + 28006,28081,28155,28230,28304,28378,28452,28525,28599,28672,28745,28818,28891,28963, + 29035,29108,29180,29251,29323,29394,29466,29537,29608,29678,29749,29819,29890,29960, + 30030,30099,30169,30238,30308,30377,30446,30515,30583,30652,30720,30788,30856,30924, + 30992,31059,31127,31194,31261,31328,31395,31462,31529,31595,31661,31727,31794,31859, + 31925,31991,32056,32122,32187,32252,32317,32382,32446,32511,32575,32640,32704,32768, + 32832,32896,32959,33023,33086,33150,33213,33276,33339,33402,33465,33527,33590,33652, + 33714,33776,33839,33900,33962,34024,34086,34147,34208,34270,34331,34392,34453,34514, + 34574,34635,34695,34756,34816,34876,34936,34996,35056,35116,35176,35235,35295,35354, + 35413,35472,35531,35590,35649,35708,35767,35825,35884,35942,36001,36059,36117,36175, + 36233,36291,36348,36406,36464,36521,36578,36636,36693,36750,36807,36864,36921,36978, + 37034,37091,37147,37204,37260,37316,37372,37429,37485,37540,37596,37652,37708,37763, + 37819,37874,37929,37985,38040,38095,38150,38205,38260,38315,38369,38424,38478,38533, + 38587,38642,38696,38750,38804,38858,38912,38966,39020,39073,39127,39181,39234,39287, + 39341,39394,39447,39500,39553,39606,39659,39712,39765,39818,39870,39923,39975,40028, + 40080,40132,40185,40237,40289,40341,40393,40445,40497,40548,40600,40652,40703,40755, + 40806,40857,40909,40960,41011,41062,41113,41164,41215,41266,41317,41368,41418,41469, + 41519,41570,41620,41671,41721,41771,41821,41871,41922,41972,42021,42071,42121,42171, + 42221,42270,42320,42369,42419,42468,42518,42567,42616,42665,42714,42763,42813,42861, + 42910,42959,43008,43057,43105,43154,43203,43251,43300,43348,43396,43445,43493,43541, + 43589,43637,43685,43733,43781,43829,43877,43925,43972,44020,44068,44115,44163,44210, + 44258,44305,44352,44400,44447,44494,44541,44588,44635,44682,44729,44776,44823,44869, + 44916,44963,45009,45056,45103,45149,45195,45242,45288,45334,45381,45427,45473,45519, + 45565,45611,45657,45703,45749,45795,45840,45886,45932,45977,46023,46069,46114,46160, + 46205,46250,46296,46341,46386,46431,46477,46522,46567,46612,46657,46702,46746,46791, + 46836,46881,46926,46970,47015,47059,47104,47149,47193,47237,47282,47326,47370,47415, + 47459,47503,47547,47591,47635,47679,47723,47767,47811,47855,47899,47942,47986,48030, + 48074,48117,48161,48204,48248,48291,48335,48378,48421,48465,48508,48551,48594,48637, + 48680,48723,48766,48809,48852,48895,48938,48981,49024,49067,49109,49152,49195,49237, + 49280,49322,49365,49407,49450,49492,49535,49577,49619,49661,49704,49746,49788,49830, + 49872,49914,49956,49998,50040,50082,50124,50166,50207,50249,50291,50332,50374,50416, + 50457,50499,50540,50582,50623,50665,50706,50747,50789,50830,50871,50912,50954,50995, + 51036,51077,51118,51159,51200,51241,51282,51323,51364,51404,51445,51486,51527,51567, + 51608,51649,51689,51730,51770,51811,51851,51892,51932,51972,52013,52053,52093,52134, + 52174,52214,52254,52294,52334,52374,52414,52454,52494,52534,52574,52614,52654,52694, + 52734,52773,52813,52853,52892,52932,52972,53011,53051,53090,53130,53169,53209,53248, + 53287,53327,53366,53405,53445,53484,53523,53562,53601,53640,53679,53719,53758,53797, + 53836,53874,53913,53952,53991,54030,54069,54108,54146,54185,54224,54262,54301,54340, + 54378,54417,54455,54494,54532,54571,54609,54647,54686,54724,54762,54801,54839,54877, + 54915,54954,54992,55030,55068,55106,55144,55182,55220,55258,55296,55334,55372,55410, + 55447,55485,55523,55561,55599,55636,55674,55712,55749,55787,55824,55862,55900,55937, + 55975,56012,56049,56087,56124,56162,56199,56236,56273,56311,56348,56385,56422,56459, + 56497,56534,56571,56608,56645,56682,56719,56756,56793,56830,56867,56903,56940,56977, + 57014,57051,57087,57124,57161,57198,57234,57271,57307,57344,57381,57417,57454,57490, + 57527,57563,57599,57636,57672,57709,57745,57781,57817,57854,57890,57926,57962,57999, + 58035,58071,58107,58143,58179,58215,58251,58287,58323,58359,58395,58431,58467,58503, + 58538,58574,58610,58646,58682,58717,58753,58789,58824,58860,58896,58931,58967,59002, + 59038,59073,59109,59144,59180,59215,59251,59286,59321,59357,59392,59427,59463,59498, + 59533,59568,59603,59639,59674,59709,59744,59779,59814,59849,59884,59919,59954,59989, + 60024,60059,60094,60129,60164,60199,60233,60268,60303,60338,60373,60407,60442,60477, + 60511,60546,60581,60615,60650,60684,60719,60753,60788,60822,60857,60891,60926,60960, + 60995,61029,61063,61098,61132,61166,61201,61235,61269,61303,61338,61372,61406,61440, + 61474,61508,61542,61576,61610,61644,61678,61712,61746,61780,61814,61848,61882,61916, + 61950,61984,62018,62051,62085,62119,62153,62186,62220,62254,62287,62321,62355,62388, + 62422,62456,62489,62523,62556,62590,62623,62657,62690,62724,62757,62790,62824,62857, + 62891,62924,62957,62991,63024,63057,63090,63124,63157,63190,63223,63256,63289,63323, + 63356,63389,63422,63455,63488,63521,63554,63587,63620,63653,63686,63719,63752,63785, + 63817,63850,63883,63916,63949,63982,64014,64047,64080,64113,64145,64178,64211,64243, + 64276,64309,64341,64374,64406,64439,64471,64504,64536,64569,64601,64634,64666,64699, + 64731,64763,64796,64828,64861,64893,64925,64957,64990,65022,65054,65086,65119,65151, + 65183,65215,65247,65279,65312,65344,65376,65408,65440,65472,65504 +}; + + +int8 g_elder_bit_table[256] = //---------g_elder_bit_table +{ + 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; + +unsigned fastint_sqrt(unsigned val) +{ + unsigned t = val; + int bit=0; + unsigned shift = 11; + bit = t >> 24; + if(bit) + bit = g_elder_bit_table[bit] + 24; + else { + bit = (t >> 16) & 0xFF; + if(bit) + bit = g_elder_bit_table[bit] + 16; + else { + bit = (t >> 8) & 0xFF; + if(bit) + bit = g_elder_bit_table[bit] + 8; + else + bit = g_elder_bit_table[t]; + } + } + bit -= 9; + if(bit > 0) { + bit = (bit >> 1) + (bit & 1); + shift -= bit; + val >>= (bit << 1); + } + return g_sqrt_table[val] >> shift; +} + +struct PainterRadialSpan : SpanSource { + LinearInterpolator interpolator; + int cx, cy, r, fx, fy; + int style; + int alpha; + RGBA gradient[2048]; + bool focus; + double C; + + void prepare() {} + + void Set(int _x, int _y, int _r, int _fx, int _fy) + { + cx = _x; + cy = _y; + r = _r; + fx = _fx; + fy = _fy; + focus = cx != fx || cy != fy; + if(focus) { + fx -= cx; + fy -= cy; + double fx2 = double(fx) * double(fx); + double fy2 = double(fy) * double(fy); + C = fx * fx + fy * fy - r * r; + } + else {//WRONG! + cx <<= 6; + cy <<= 6; + r <<= 6; + } + } + + void Get(RGBA *_span, int x, int y, unsigned len) + { + if(r <= 0) + return; + interpolator.Begin(x, y, len); + RGBA *span = (RGBA *)_span; + while(len--) { + interpolator.Get(x, y); + int h; + if(focus) { + const double q256 = 1 / 256.0; + double dx = q256 * x - cx - fx; + double dy = q256 * y - cy - fy; + if(dx == 0 && dy == 0) + h = 0; + else { + double A = dx * dx + dy * dy; + double b = (fx * dx + fy * dy); + double t = (sqrt(b * b - A * C) - b) / (A); + h = t >= 0.001 ? int(2047 / t) : 2047; + } + } + else { + x >>= 2; + y >>= 2; + int dc = Upp::fastint_sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)); + h = 2047 * dc / r; + } + if(style == GRADIENT_REPEAT) + h = h & 2047; + else + if(style == GRADIENT_REFLECT) + h = (h & 2048) ? (2047 - h & 2047) : (h & 2047); + else + h = minmax(h, 0, 2047); + *span++ = gradient[h]; + } + } +}; + +void BufferPainter::RenderRadial(double width, const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, int style) +{ + PainterRadialSpan sg; + sg.interpolator.Set(Inverse(pathattr.mtx)); + sg.style = style; + sg.Set((int)c.x, (int)c.y, (int)r, (int)f.x, (int)f.y); + MakeGradient(sg.gradient, color1, color2, 2048); + RenderPath(width, &sg, RGBAZero()); +} + +void BufferPainter::FillOp(const Pointf& f, const RGBA& color1, const Pointf& c, double r, const RGBA& color2, int style) +{ + RenderRadial(-1, f, color1, c, r, color2, style); +} + +void BufferPainter::StrokeOp(double width, const Pointf& f, const RGBA& color1, const Pointf& c, double r, const RGBA& color2, int style) +{ + RenderRadial(width, f, color1, c, r, color2, style); +} + +END_UPP_NAMESPACE diff --git a/uppdev/Painter/Rasterizer.cpp b/uppdev/Painter/Rasterizer.cpp index a911fff2b..00d3fefe4 100644 --- a/uppdev/Painter/Rasterizer.cpp +++ b/uppdev/Painter/Rasterizer.cpp @@ -30,6 +30,7 @@ Rasterizer::Rasterizer(int cx, int cy) sz.cy = cy; cell.Alloc(sz.cy + 1); cliprect = Sizef(sz); + Init(); Reset(); } diff --git a/uppdev/Painter/RasterizerClip.cpp b/uppdev/Painter/RasterizerClip.cpp index 7dbf26842..1578ea9a9 100644 --- a/uppdev/Painter/RasterizerClip.cpp +++ b/uppdev/Painter/RasterizerClip.cpp @@ -4,14 +4,9 @@ NAMESPACE_UPP -inline int Cv(double x) -{ - return int(x * 256 + 0.5); -} - void Rasterizer::CvLine(double x1, double y1, double x2, double y2) { - LineRaw(Cv(x1), Cv(y1), Cv(x2), Cv(y2)); + LineRaw(Q8(x1), Q8(y1), Q8(x2), Q8(y2)); } void Rasterizer::LineClip(double x1, double y1, double x2, double y2) diff --git a/uppdev/Painter/Render.cpp b/uppdev/Painter/Render.cpp index 8b6fe4a96..ee6886136 100644 --- a/uppdev/Painter/Render.cpp +++ b/uppdev/Painter/Render.cpp @@ -7,19 +7,37 @@ void BufferPainter::ClearOp(const RGBA& color) UPP::Fill(~ib, color, ib.GetLength()); } -void BufferPainter::RenderPath(LinearPathFilter *first_filter, - LinearPathFilter *last_filter, const RGBA& color, bool evenodd) +void BufferPainter::RenderPath(double width, SpanSource *ss, const RGBA& color) { + if(width == 0) + return; Transformer trans(pathattr.mtx); trans.target = &rasterizer; LinearPathConsumer *g; - if(first_filter) { - last_filter->target = &trans; - g = first_filter; + 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 + else { + Close(); g = &trans; + } byte *data = path.data; + int opacity = int(256 * pathattr.opacity); + RGBA c; + if(!ss) + c = Mul8(color, opacity); Pointf pos = Pointf(0, 0); { PAINTER_TIMING("Pipeline"); @@ -59,27 +77,25 @@ void BufferPainter::RenderPath(LinearPathFilter *first_filter, } } g->End(); - Render(ib, rasterizer, color, evenodd); + if(ss) { + if(!span) + span.Alloc(ib.GetWidth() + 1); + Render(ib, rasterizer, ss, span, opacity, evenodd); + } + else + Render(ib, rasterizer, c, evenodd); rasterizer.Reset(); current = Null; } void BufferPainter::FillOp(const RGBA& color) { - Close(); - RenderPath(NULL, NULL, color, pathattr.evenodd); + RenderPath(-1, NULL, color); } void BufferPainter::StrokeOp(double width, const RGBA& color) { - Stroker stroker(width, pathattr.miter_limit, pathattr.tolerance, pathattr.cap, pathattr.join); - if(pathattr.dash.GetCount()) { - Dasher dasher(pathattr.dash, pathattr.dash_start); - dasher.target = &stroker; - RenderPath(&dasher, &stroker, color, false); - } - else - RenderPath(&stroker, &stroker, color, false); + RenderPath(width, NULL, color); } END_UPP_NAMESPACE diff --git a/uppdev/Painter/SolidFiller.cpp b/uppdev/Painter/SolidFiller.cpp index dce7e1021..89524c8de 100644 --- a/uppdev/Painter/SolidFiller.cpp +++ b/uppdev/Painter/SolidFiller.cpp @@ -70,20 +70,41 @@ void Render(ImageBuffer& ib, Rasterizer& r, const RGBA& color, bool evenodd) } struct SpanFiller : Rasterizer::Target { - RGBA *t; + RGBA *t; const RGBA *s; + int y; + RGBA *buffer; + SpanSource *ss; + int alpha; - void Start(int minx, int maxx) { t += minx; } - void Render(int val) { AlphaBlendCover8(*t++, *s++, val); } + void Start(int minx, int maxx); + void Render(int val); void Render(int val, int len); }; +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; return; } + const RGBA *e = t + len; + if(alpha != 256) + val = alpha * val >> 8; if(val == 256) while(t < e) { if(s->a == 255) @@ -96,13 +117,16 @@ void SpanFiller::Render(int val, int len) AlphaBlendCover8(*t++, *s++, val); } -void Render(ImageBuffer& ib, Rasterizer& r, const RGBA& color, bool evenodd) +void Render(ImageBuffer& ib, Rasterizer& r, SpanSource *s, RGBA *buffer, int alpha, bool evenodd) { Size sz = ib.GetSize(); - SolidFiller f; - f.c = color; + SpanFiller f; + f.ss = s; + f.buffer = buffer; + f.alpha = alpha; for(int y = r.MinY(); y <= r.MaxY(); y++) { f.t = ib[y]; + f.y = y; r.Render(y, f, evenodd); } r.Reset(); diff --git a/uppdev/Painter/Stroker.cpp b/uppdev/Painter/Stroker.cpp index 833ebaeb6..840306697 100644 --- a/uppdev/Painter/Stroker.cpp +++ b/uppdev/Painter/Stroker.cpp @@ -4,10 +4,10 @@ NAMESPACE_UPP -Stroker::Stroker(double width, double miterlimit, double tolerance, int linecap, int linejoin) -: linecap(linecap), - linejoin(linejoin) +void Stroker::Init(double width, double miterlimit, double tolerance, int _linecap, int _linejoin) { + linecap = _linecap; + linejoin = _linejoin; w2 = width / 2; qmiter = miterlimit * w2; qmiter *= qmiter; diff --git a/uppdev/Painter/Text.cpp b/uppdev/Painter/Text.cpp new file mode 100644 index 000000000..4a426b7fe --- /dev/null +++ b/uppdev/Painter/Text.cpp @@ -0,0 +1,51 @@ +#include "Painter.h" + +NAMESPACE_UPP + +void Painter::TextOp(double x, double y, const wchar *text, Font fnt, int n, double *dx) +{ + FontInfo fi = fnt.Info(); + if(n < 0) + n = wstrlen(text); + while(n) { + int ch = *text++; + Character(x, y, ch, fnt); + if(dx) + x += *dx++; + else + x += fi[ch]; + n--; + } +} + +Painter& Painter::Character(double x, double y, int ch, Font fnt) +{ + CharacterOp(x, y, ch, fnt); + return *this; +} + +Painter& Painter::Text(double x, double y, const wchar *text, Font fnt, int n, double *dx) +{ + TextOp(x, y, text, fnt, n, dx); + return *this; +} + +Painter& Painter::Text(double x, double y, const WString& s, Font fnt, double *dx) +{ + Text(x, y, s, fnt, s.GetLength(), dx); + return *this; +} + +Painter& Painter::Text(double x, double y, const String& s, Font fnt, double *dx) +{ + Text(x, y, s.ToWString(), fnt, dx); + return *this; +} + +Painter& Painter::Text(double x, double y, const char *text, Font fnt, int n, double *dx) +{ + Text(x, y, ToUnicode(text, n < 0 ? strlen(text) : n, CHARSET_DEFAULT), fnt, dx); + return *this; +} + +END_UPP_NAMESPACE diff --git a/uppdev/Painter/Xform2D.cpp b/uppdev/Painter/Xform2D.cpp index e70a7eeca..5deb62e4a 100644 --- a/uppdev/Painter/Xform2D.cpp +++ b/uppdev/Painter/Xform2D.cpp @@ -24,6 +24,12 @@ bool Xform2D::IsRegular() const 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; @@ -40,7 +46,6 @@ Xform2D Xform2D::Translation(double x, double y) { Xform2D m; m.x.x = m.y.y = 1; - m.x.y = m.y.x = 0; m.t = Pointf(x, y); return m; } @@ -50,7 +55,6 @@ Xform2D Xform2D::Scale(double sx, double sy) Xform2D m; m.x.x = sx; m.y.y = sy; - m.x.y = m.y.x = m.t.x = m.t.y = 0; return m; } @@ -76,7 +80,6 @@ Xform2D Xform2D::Sheer(double fi) { Xform2D m; m.x.x = m.y.y = 1; - m.y.x = m.t.x = m.t.y = 0; m.x.y = atan(fi); return m; } @@ -85,7 +88,6 @@ Xform2D Xform2D::Identity() { Xform2D m; m.x.x = m.y.y = 1; - m.x.y = m.y.x = m.t.x = m.t.y = 0; return m; } @@ -100,8 +102,8 @@ Xform2D Inverse(const Xform2D& m) 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 * m.x.x - m.t.y * m.x.y; - r.t.y = -m.t.x * m.y.x - m.t.y * m.y.y; + 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; } diff --git a/uppdev/PainterExamples/ColorStops.cpp b/uppdev/PainterExamples/ColorStops.cpp index f7db7869f..fb73dab35 100644 --- a/uppdev/PainterExamples/ColorStops.cpp +++ b/uppdev/PainterExamples/ColorStops.cpp @@ -1,7 +1,5 @@ #include "Examples.h" -#if 0 - void GradientStop(Painter& sw) { sw.Rectangle(20.5, 20.5, 500, 100) @@ -15,5 +13,3 @@ void GradientStop(Painter& sw) INITBLOCK { RegisterExample("Gradient stops", GradientStop); } - -#endif diff --git a/uppdev/PainterExamples/Dash.cpp b/uppdev/PainterExamples/Dash.cpp index c10b78225..9a490dcce 100644 --- a/uppdev/PainterExamples/Dash.cpp +++ b/uppdev/PainterExamples/Dash.cpp @@ -3,6 +3,14 @@ void Dash(Painter& sw) { sw.Move(50, 50).Line(400, 200).Dash("2").Stroke(5, Blue()); + sw.Translate(0, 10); + sw.Move(50, 50).Line(400, 200).Dash("10 5").Stroke(5, Blue()); + sw.Translate(0, 10); + sw.Move(50, 50).Line(400, 200).Dash("10 5 5 5").Stroke(5, Blue()); + sw.Translate(0, 10); + sw.Move(50, 50).Line(400, 200).Dash("1").Stroke(5, Blue()); + sw.Translate(0, 10); + sw.Move(50, 50).Line(400, 200).Dash("1 2 3 4 5").Stroke(5, Blue()); } INITBLOCK { diff --git a/uppdev/PainterExamples/Gradient.cpp b/uppdev/PainterExamples/Gradient.cpp index 315a90212..1976f1381 100644 --- a/uppdev/PainterExamples/Gradient.cpp +++ b/uppdev/PainterExamples/Gradient.cpp @@ -1,7 +1,5 @@ #include "Examples.h" -#if 0 - void FillGradient(Painter& sw) { sw.Rectangle(10, 10, 1000, 600) @@ -28,5 +26,3 @@ INITBLOCK { RegisterExample("Linear gradient - REFLECT", FillGradientReflect); RegisterExample("Linear gradient - REPEAT", FillGradientRepeat); } - -#endif diff --git a/uppdev/PainterExamples/Image.cpp b/uppdev/PainterExamples/Image.cpp index 09c9e4e65..8663cbbf5 100644 --- a/uppdev/PainterExamples/Image.cpp +++ b/uppdev/PainterExamples/Image.cpp @@ -1,19 +1,30 @@ #include "Examples.h" -#if 0 - void ImageExact(Painter& sw) { sw.Rectangle(10, 10, 1000, 600) -// .Fill(TestImg::test(), 200, 100, 300, 300) _DBG_ .Fill(TestImg::test(), 100, 100, 500, 100) .Stroke(2, Black()); } +void ImageExactFast(Painter& sw) +{ + sw.Rectangle(10, 10, 1000, 600) + .Fill(TestImg::test(), 100, 100, 500, 100, FILL_FAST) + .Stroke(2, Black()); +/* + int cx = 400; + for(int l = 0; l < 5; l++) { + sw.Translate(cx, 0); + cx /= 2; + sw.Rectangle(10, 10, 1000, 600) + .Fill(MakeMipMap(TestImg::test(), l), 100, 100, 100 + cx, 100, FILL_FAST); + }*/ +} + void ImageReflect(Painter& sw) { sw.Rectangle(10, 10, 1000, 600) -// .Fill(TestImg::test(), 200, 100, 300, 300, GRADIENT_REFLECT) _DBG_ .Fill(TestImg::test(), 100, 100, 500, 100, FILL_REFLECT) .Stroke(2, Black()); } @@ -41,10 +52,9 @@ void ImageRepeat(Painter& sw) INITBLOCK { RegisterExample("Image fill exact", ImageExact); + RegisterExample("Image fill exact fast", ImageExactFast); RegisterExample("Image fill reflect", ImageReflect); RegisterExample("Image fill pad", ImagePad); RegisterExample("Image fill repeat", ImageRepeat); RegisterExample("Image vpad&hreflect", ImageVPadHReflect); } - -#endif diff --git a/uppdev/PainterExamples/Lion.cpp b/uppdev/PainterExamples/Lion.cpp index 94d8de036..e75a2184e 100644 --- a/uppdev/PainterExamples/Lion.cpp +++ b/uppdev/PainterExamples/Lion.cpp @@ -189,7 +189,6 @@ void PaintLion(Painter& sw) } } -/* void Demo(Painter& sw) { PaintLion(sw); @@ -200,7 +199,6 @@ void Demo(Painter& sw) .Fill(TestImg::test(), 0, 400, 500, 400, FILL_REFLECT) .Stroke(5, 0, 500, Blue(), tsz.cx, 500, LtRed()) .Stroke(1, White()); - for(int i = 0; i < 10; i++) { sw.Begin(); sw.Opacity(0.5); @@ -211,9 +209,8 @@ void Demo(Painter& sw) sw.End(); } } -*/ INITBLOCK { RegisterExample("Lion", PaintLion); -// RegisterExample("U++ Painter", Demo); + RegisterExample("U++ Painter", Demo); } diff --git a/uppdev/PainterExamples/PainterExamples.upp b/uppdev/PainterExamples/PainterExamples.upp index 2d795ea33..469bd0f82 100644 --- a/uppdev/PainterExamples/PainterExamples.upp +++ b/uppdev/PainterExamples/PainterExamples.upp @@ -1,4 +1,4 @@ -description "Antialiased renderer class, Painter, examples"; +description "Antialiased renderer class, Painter, examples, version 2.0"; uses CtrlLib, diff --git a/uppdev/PainterExamples/Path.cpp b/uppdev/PainterExamples/Path.cpp index 813828d7e..3d5f7ab2d 100644 --- a/uppdev/PainterExamples/Path.cpp +++ b/uppdev/PainterExamples/Path.cpp @@ -1,7 +1,5 @@ #include "Examples.h" -#if 0 - void Path(Painter& sw) { sw.Translate(52, 52); @@ -19,5 +17,3 @@ void Path(Painter& sw) INITBLOCK { RegisterExample("Path example", Path); } - -#endif diff --git a/uppdev/PainterExamples/Pythagoras.cpp b/uppdev/PainterExamples/Pythagoras.cpp index 9428daa7e..2a1f0424a 100644 --- a/uppdev/PainterExamples/Pythagoras.cpp +++ b/uppdev/PainterExamples/Pythagoras.cpp @@ -9,11 +9,9 @@ void DoRect(Painter &sw, double size, bool image) sw.Line(0, size); sw.Line(size, size); sw.Line(size, 0); -#if 0 if(image) sw.Fill(TestImg::test(), 0, 0, size, 0); else -#endif sw.Fill(Blue()); sw.Begin(); @@ -38,8 +36,6 @@ void PythagorasTree(Painter& sw) sw.End(); } -#if 0 - void PythagorasTreeImage(Painter& sw) { sw.Begin(); @@ -48,9 +44,8 @@ void PythagorasTreeImage(Painter& sw) DoRect(sw, 160, true); sw.End(); } -#endif INITBLOCK { RegisterExample("Pythagoras tree", PythagorasTree); -// RegisterExample("Pythagoras tree image", PythagorasTreeImage); + RegisterExample("Pythagoras tree image", PythagorasTreeImage); } diff --git a/uppdev/PainterExamples/RadialFocus.cpp b/uppdev/PainterExamples/RadialFocus.cpp index ae2be6c3f..ea83da850 100644 --- a/uppdev/PainterExamples/RadialFocus.cpp +++ b/uppdev/PainterExamples/RadialFocus.cpp @@ -1,13 +1,13 @@ #include "Examples.h" #if 0 - void RadialFocus(Painter& sw) { sw.Circle(400.5, 400.5, 200) .Fill(300, 300, White(), 400.5, 400.5, 200, LtBlue()) ; } +#endif void RadialFocusPad(Painter& sw) { @@ -34,10 +34,8 @@ void RadialFocusRepeat(Painter& sw) } INITBLOCK { - RegisterExample("Radial gradient - focus", RadialFocus); +// RegisterExample("Radial gradient - focus", RadialFocus); RegisterExample("Radial gradient - focus - PAD", RadialFocusPad); RegisterExample("Radial gradient - focus - REFLECT", RadialFocusReflect); RegisterExample("Radial gradient - focus - REPEAT", RadialFocusRepeat); } - -#endif diff --git a/uppdev/PainterExamples/Spiral.cpp b/uppdev/PainterExamples/Spiral.cpp index d4941055f..bb10ddaa7 100644 --- a/uppdev/PainterExamples/Spiral.cpp +++ b/uppdev/PainterExamples/Spiral.cpp @@ -1,7 +1,5 @@ #include "Examples.h" -#if 0 - void PathSpiral(Painter& sw) { sw.Path("M153 334 C153 334 151 334 151 334 C151 339 153 344 156 344 C164 344 171 339 171 334 " @@ -14,5 +12,3 @@ void PathSpiral(Painter& sw) INITBLOCK { RegisterExample("Path spiral", PathSpiral); } - -#endif \ No newline at end of file diff --git a/uppdev/PainterExamples/Stroke.cpp b/uppdev/PainterExamples/Stroke.cpp index fd0a70ede..fbcf502aa 100644 --- a/uppdev/PainterExamples/Stroke.cpp +++ b/uppdev/PainterExamples/Stroke.cpp @@ -1,10 +1,8 @@ #include "Examples.h" -#if 0 - void Stroke(Painter& sw) { - const char *txt = "GRM";//ADIENT TEXT"; + const char *txt = "GRM"; Font fnt = Arial(100).Bold(); Size tsz = GetTextSize(txt, fnt); sw.Scale(3, 3); @@ -18,5 +16,3 @@ void Stroke(Painter& sw) INITBLOCK { RegisterExample("Stroke", Stroke); } - -#endif diff --git a/uppdev/PainterExamples/TextFillGradient.cpp b/uppdev/PainterExamples/TextFillGradient.cpp index 8c01c10f8..19975d37e 100644 --- a/uppdev/PainterExamples/TextFillGradient.cpp +++ b/uppdev/PainterExamples/TextFillGradient.cpp @@ -1,7 +1,5 @@ #include "Examples.h" -#if 0 - void TextFillGradient(Painter& sw) { const char *txt = "GRADIENT TEXT"; @@ -14,5 +12,3 @@ void TextFillGradient(Painter& sw) INITBLOCK { RegisterExample("Filling text with linear gradient", TextFillGradient); } - -#endif diff --git a/uppdev/PainterExamples/TextFillSolid.cpp b/uppdev/PainterExamples/TextFillSolid.cpp index def88c365..23ada2b68 100644 --- a/uppdev/PainterExamples/TextFillSolid.cpp +++ b/uppdev/PainterExamples/TextFillSolid.cpp @@ -1,7 +1,5 @@ #include "Examples.h" -#if 0 - void TextFillSolid(Painter& sw) { sw.Text(100, 100, "Hello world!", Roman(120).Italic().Bold()) @@ -11,5 +9,3 @@ void TextFillSolid(Painter& sw) INITBLOCK { RegisterExample("Filling text with solid color", TextFillSolid); } - -#endif diff --git a/uppdev/PainterExamples/TextStrokeGradient.cpp b/uppdev/PainterExamples/TextStrokeGradient.cpp index 765d564ac..4bed1594d 100644 --- a/uppdev/PainterExamples/TextStrokeGradient.cpp +++ b/uppdev/PainterExamples/TextStrokeGradient.cpp @@ -1,7 +1,5 @@ #include "Examples.h" -#if 0 - void TextStrokeGradient(Painter& sw) { const char *txt = "GRADIENT TEXT"; @@ -14,5 +12,3 @@ void TextStrokeGradient(Painter& sw) INITBLOCK { RegisterExample("Stroking text with linear gradient", TextStrokeGradient); } - -#endif diff --git a/uppdev/PainterExamples/ThinLine.cpp b/uppdev/PainterExamples/ThinLine.cpp index 8b0afc745..3af25d24f 100644 --- a/uppdev/PainterExamples/ThinLine.cpp +++ b/uppdev/PainterExamples/ThinLine.cpp @@ -2,7 +2,7 @@ void ThinPolygon(Painter& sw) { -// sw.Translate(52, 52); + sw.Translate(52, 52); for(int i = 0; i < 2; i++) { sw.Move(36.000000, 142.000000); sw.Line(480.000000, 148.000000);