mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-21 06:45:39 -06:00
Painter fixed to work in Linux, MoveableWithSwap removed (GCC problems, possibly undefined behaviour of code)
git-svn-id: svn://ultimatepp.org/upp/trunk@867 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
f2f2348907
commit
dd88989c82
13 changed files with 2005 additions and 2045 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,352 +1,352 @@
|
|||
Pointf Mid(const Pointf& a, const Pointf& b);
|
||||
Pointf Orthogonal(const Pointf& p);
|
||||
double Squared(const Pointf& p);
|
||||
double Length(const Pointf& p);
|
||||
double Bearing(const Pointf& p);
|
||||
double Distance(const Pointf& p1, const Pointf& p2);
|
||||
double SquaredDistance(const Pointf& p1, const Pointf& p2);
|
||||
Pointf Polar(double a);
|
||||
Pointf Polar(const Pointf& p, double r, double a);
|
||||
|
||||
struct LinearPathConsumer {
|
||||
virtual void Move(const Pointf& p) = 0;
|
||||
virtual void Line(const Pointf& p) = 0;
|
||||
virtual void End();
|
||||
};
|
||||
|
||||
void ApproximateQuadratic(LinearPathConsumer& t,
|
||||
const Pointf& p1, const Pointf& p2, const Pointf& p3,
|
||||
double tolerance);
|
||||
void ApproximateCubic(LinearPathConsumer& t,
|
||||
const Pointf& x0, const Pointf& x1, const Pointf& x2, const Pointf& x,
|
||||
double tolerance);
|
||||
void ApproximateArc(LinearPathConsumer& t, const Pointf& p, const Pointf& r,
|
||||
double angle, double sweep, double tolerance);
|
||||
|
||||
struct LinearPathFilter : LinearPathConsumer {
|
||||
virtual void End();
|
||||
|
||||
LinearPathConsumer *target;
|
||||
|
||||
void PutMove(const Pointf& p) { target->Move(p); }
|
||||
void PutLine(const Pointf& p) { target->Line(p); }
|
||||
void PutEnd() { target->End(); }
|
||||
};
|
||||
|
||||
class Stroker : public LinearPathFilter {
|
||||
public:
|
||||
virtual void Move(const Pointf& p);
|
||||
virtual void Line(const Pointf& p);
|
||||
virtual void End();
|
||||
|
||||
private:
|
||||
double w2;
|
||||
double qmiter;
|
||||
double fid;
|
||||
|
||||
Pointf p0, v0, o0, a0, b0;
|
||||
Pointf p1, v1, o1, a1, b1;
|
||||
Pointf p2;
|
||||
int linecap;
|
||||
int linejoin;
|
||||
|
||||
void Finish();
|
||||
void Round(const Pointf& p, const Pointf& v1, const Pointf& v2, double r);
|
||||
void Cap(const Pointf& p0, const Pointf& v0, const Pointf& o0,
|
||||
const Pointf& a0, const Pointf& b0);
|
||||
|
||||
public:
|
||||
void Init(double width, double miterlimit, double tolerance, int linecap, int linejoin);
|
||||
};
|
||||
|
||||
class Dasher : public LinearPathFilter {
|
||||
public:
|
||||
virtual void Move(const Pointf& p);
|
||||
virtual void Line(const Pointf& p);
|
||||
|
||||
private:
|
||||
const Vector<double> *pattern;
|
||||
int patterni;
|
||||
double sum, rem;
|
||||
bool flag;
|
||||
Pointf p0;
|
||||
|
||||
void Put(const Pointf& p);
|
||||
|
||||
public:
|
||||
void Init(const Vector<double>& pattern, double distance);
|
||||
};
|
||||
|
||||
struct Transformer : public LinearPathFilter {
|
||||
public:
|
||||
virtual void Move(const Pointf& p);
|
||||
virtual void Line(const Pointf& p);
|
||||
|
||||
private:
|
||||
const Xform2D& xform;
|
||||
|
||||
public:
|
||||
Transformer(const Xform2D& xform) : xform(xform) {}
|
||||
};
|
||||
|
||||
inline RGBA Mul8(const RGBA& s, int mul)
|
||||
{
|
||||
RGBA t;
|
||||
t.r = (mul * s.r) >> 8;
|
||||
t.g = (mul * s.g) >> 8;
|
||||
t.b = (mul * s.b) >> 8;
|
||||
t.a = (mul * s.a) >> 8;
|
||||
return t;
|
||||
}
|
||||
|
||||
inline void AlphaBlend(RGBA& t, const RGBA& c)
|
||||
{
|
||||
int alpha = 256 - (c.a + (c.a >> 7));
|
||||
t.r = c.r + (alpha * t.r >> 8);
|
||||
t.g = c.g + (alpha * t.g >> 8);
|
||||
t.b = c.b + (alpha * t.b >> 8);
|
||||
t.a = c.a + (alpha * t.a >> 8);
|
||||
}
|
||||
|
||||
inline void AlphaBlendCover8(RGBA& t, const RGBA& c, int cover)
|
||||
{
|
||||
int a = c.a * cover >> 8;
|
||||
int alpha = 256 - (a + (a >> 7));
|
||||
t.r = (c.r * cover >> 8) + (alpha * t.r >> 8);
|
||||
t.g = (c.g * cover >> 8) + (alpha * t.g >> 8);
|
||||
t.b = (c.b * cover >> 8) + (alpha * t.b >> 8);
|
||||
t.a = a + (alpha * t.a >> 8);
|
||||
}
|
||||
|
||||
inline int Q8(double x)
|
||||
{
|
||||
return int(x * 256 + 0.5);
|
||||
}
|
||||
|
||||
class Rasterizer : public LinearPathConsumer {
|
||||
public:
|
||||
virtual void Move(const Pointf& p);
|
||||
virtual void Line(const Pointf& p);
|
||||
|
||||
private:
|
||||
struct Cell : MoveableWithSwap<Cell> {
|
||||
int16 x;
|
||||
int16 cover;
|
||||
int area;
|
||||
|
||||
bool operator<(const Cell& b) const { return x < b.x; }
|
||||
};
|
||||
|
||||
Rectf cliprect;
|
||||
Pointf p0;
|
||||
Buffer< Vector<Cell> > cell;
|
||||
int min_y;
|
||||
int max_y;
|
||||
Size sz;
|
||||
|
||||
void Init();
|
||||
Cell *AddCells(int y, int n);
|
||||
void RenderHLine(int ey, int x1, int y1, int x2, int y2);
|
||||
void LineClip(double x1, double y1, double x2, double y2);
|
||||
int CvX(double x);
|
||||
int CvY(double y);
|
||||
void CvLine(double x1, double y1, double x2, double y2);
|
||||
bool BeginRender(int y, const Cell *&c, const Cell *&e);
|
||||
|
||||
public:
|
||||
struct Filler {
|
||||
virtual void Start(int x, int len) = 0;
|
||||
virtual void Render(int val) = 0;
|
||||
virtual void Render(int val, int len) = 0;
|
||||
};
|
||||
|
||||
void LineRaw(int x1, int y1, int x2, int y2);
|
||||
|
||||
void SetClip(const Rectf& rect);
|
||||
|
||||
int MinY() const { return min_y; }
|
||||
int MaxY() const { return max_y; }
|
||||
void Render(int y, Filler& g, bool evenodd);
|
||||
|
||||
void Reset();
|
||||
|
||||
Rasterizer(int cx, int cy);
|
||||
};
|
||||
|
||||
struct SpanSource {
|
||||
virtual void Get(RGBA *span, int x, int y, unsigned len) = 0;
|
||||
};
|
||||
|
||||
class ClipLine : NoCopy {
|
||||
byte *data;
|
||||
|
||||
public:
|
||||
void Clear() { if(!IsFull()) delete[] data; data = NULL; }
|
||||
void Set(const byte *s, int len) { data = new byte[len]; memcpy(data, s, len); }
|
||||
void SetFull() { ASSERT(!data); data = (byte *)1; }
|
||||
|
||||
bool IsEmpty() const { return !data; }
|
||||
bool IsFull() const { return data == (byte *)1; }
|
||||
operator const byte*() const { return data; }
|
||||
|
||||
ClipLine() { data = NULL; }
|
||||
~ClipLine() { Clear(); }
|
||||
};
|
||||
|
||||
Image MipMap(const Image& img);
|
||||
Image MakeMipMap(const Image& img, int level);
|
||||
|
||||
class LinearInterpolator {
|
||||
struct Dda2 {
|
||||
int count, lift, rem, mod, p;
|
||||
|
||||
void Set(int a, int b, int len);
|
||||
int Get();
|
||||
};
|
||||
|
||||
Xform2D xform;
|
||||
Dda2 ddax, dday;
|
||||
|
||||
public:
|
||||
void Set(const Xform2D& m) { xform = m; }
|
||||
|
||||
void Begin(int x, int y, int len);
|
||||
Point Get();
|
||||
};
|
||||
|
||||
class BufferPainter : public Painter {
|
||||
protected:
|
||||
virtual void ClearOp(const RGBA& color);
|
||||
|
||||
virtual void MoveOp(const Pointf& p, bool rel);
|
||||
virtual void LineOp(const Pointf& p, bool rel);
|
||||
virtual void QuadraticOp(const Pointf& p1, const Pointf& p, bool rel);
|
||||
virtual void QuadraticOp(const Pointf& p, bool rel);
|
||||
virtual void CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel);
|
||||
virtual void CubicOp(const Pointf& p2, const Pointf& p, bool rel);
|
||||
virtual void ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel);
|
||||
virtual void SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep,
|
||||
const Pointf& p, bool rel);
|
||||
virtual void CloseOp();
|
||||
virtual void DivOp();
|
||||
|
||||
virtual void FillOp(const RGBA& color);
|
||||
virtual void FillOp(const Image& image, const Xform2D& transsrc, dword flags);
|
||||
virtual void FillOp(const Pointf& p1, const RGBA& color1,
|
||||
const Pointf& p2, const RGBA& color2,
|
||||
int style);
|
||||
virtual void FillOp(const Pointf& f, const RGBA& color1,
|
||||
const Pointf& c, double r, const RGBA& color2,
|
||||
int style);
|
||||
|
||||
virtual void StrokeOp(double width, const RGBA& rgba);
|
||||
virtual void StrokeOp(double width, const Image& image, const Xform2D& transsrc,
|
||||
dword flags);
|
||||
virtual void StrokeOp(double width, const Pointf& p1, const RGBA& color1,
|
||||
const Pointf& p2, const RGBA& color2,
|
||||
int style);
|
||||
virtual void StrokeOp(double width, const Pointf& f, const RGBA& color1,
|
||||
const Pointf& c, double r, const RGBA& color2,
|
||||
int style);
|
||||
|
||||
virtual void ClipOp();
|
||||
|
||||
virtual void ColorStopOp(double pos, const RGBA& color);
|
||||
virtual void ClearStopsOp();
|
||||
|
||||
virtual void OpacityOp(double o);
|
||||
virtual void LineCapOp(int linecap);
|
||||
virtual void LineJoinOp(int linejoin);
|
||||
virtual void MiterLimitOp(double l);
|
||||
virtual void EvenOddOp(bool evenodd);
|
||||
virtual void DashOp(const Vector<double>& dash, double start);
|
||||
virtual void NoAAOp(bool noaa);
|
||||
|
||||
virtual void TransformOp(const Xform2D& m);
|
||||
|
||||
virtual void BeginOp();
|
||||
virtual void EndOp();
|
||||
|
||||
virtual void BeginMaskOp();
|
||||
|
||||
public:
|
||||
enum {
|
||||
MOVE, LINE, QUADRATIC, CUBIC, ARC, DIV
|
||||
};
|
||||
struct LinearData {
|
||||
Pointf p;
|
||||
};
|
||||
struct QuadraticData : LinearData {
|
||||
Pointf p1;
|
||||
};
|
||||
struct CubicData : QuadraticData {
|
||||
Pointf p2;
|
||||
};
|
||||
struct ArcData : LinearData {
|
||||
Pointf r;
|
||||
double angle, sweep;
|
||||
|
||||
Pointf EndPoint() const;
|
||||
};
|
||||
struct Path {
|
||||
Vector<byte> type;
|
||||
Vector<byte> data;
|
||||
};
|
||||
struct Attr : Moveable<Attr> {
|
||||
Xform2D mtx;
|
||||
double tolerance;
|
||||
bool evenodd;
|
||||
byte join;
|
||||
byte cap;
|
||||
double miter_limit;
|
||||
WithDeepCopy< Vector<double> > dash;
|
||||
WithDeepCopy< Vector<double> > stop;
|
||||
WithDeepCopy< Vector<RGBA> > stop_color;
|
||||
double dash_start;
|
||||
double opacity;
|
||||
int cliplevel;
|
||||
bool hasclip;
|
||||
bool mask;
|
||||
bool noaa;
|
||||
};
|
||||
|
||||
ImageBuffer& ib;
|
||||
|
||||
Attr attr;
|
||||
Attr pathattr;
|
||||
Array<Attr> attrstack;
|
||||
Vector< Buffer<ClipLine> > clip;
|
||||
Array< ImageBuffer > mask;
|
||||
|
||||
|
||||
Image gradient;
|
||||
RGBA gradient1, gradient2;
|
||||
int gradientn;
|
||||
|
||||
Path path;
|
||||
Pointf current, ccontrol, qcontrol, move;
|
||||
Rectf pathrect;
|
||||
|
||||
Rasterizer rasterizer;
|
||||
Buffer<RGBA> span;
|
||||
|
||||
void *PathAddRaw(int type, int size);
|
||||
template <class T> T& PathAdd(int type) { return *(T *)PathAddRaw(type, sizeof(T)); }
|
||||
|
||||
Pointf PathPoint(const Pointf& p, bool rel);
|
||||
Pointf EndPoint(const Pointf& p, bool rel);
|
||||
void DoMove0();
|
||||
void ClearPath();
|
||||
Buffer<ClipLine> RenderPath(double width, SpanSource *ss, const RGBA& color);
|
||||
void RenderImage(double width, const Image& image, const Xform2D& transsrc,
|
||||
dword flags);
|
||||
void RenderRadial(double width, const Pointf& f, const RGBA& color1,
|
||||
const Pointf& c, double r, const RGBA& color2, int style);
|
||||
void MakeGradient(RGBA color1, RGBA color2, int cx);
|
||||
void Gradient(const RGBA& color1, const RGBA& color2, const Pointf& p1, const Pointf& p2);
|
||||
void ColorStop0(Attr& a, double pos, const RGBA& color);
|
||||
void FinishMask();
|
||||
|
||||
public:
|
||||
BufferPainter(ImageBuffer& ib);
|
||||
};
|
||||
Pointf Mid(const Pointf& a, const Pointf& b);
|
||||
Pointf Orthogonal(const Pointf& p);
|
||||
double Squared(const Pointf& p);
|
||||
double Length(const Pointf& p);
|
||||
double Bearing(const Pointf& p);
|
||||
double Distance(const Pointf& p1, const Pointf& p2);
|
||||
double SquaredDistance(const Pointf& p1, const Pointf& p2);
|
||||
Pointf Polar(double a);
|
||||
Pointf Polar(const Pointf& p, double r, double a);
|
||||
|
||||
struct LinearPathConsumer {
|
||||
virtual void Move(const Pointf& p) = 0;
|
||||
virtual void Line(const Pointf& p) = 0;
|
||||
virtual void End();
|
||||
};
|
||||
|
||||
void ApproximateQuadratic(LinearPathConsumer& t,
|
||||
const Pointf& p1, const Pointf& p2, const Pointf& p3,
|
||||
double tolerance);
|
||||
void ApproximateCubic(LinearPathConsumer& t,
|
||||
const Pointf& x0, const Pointf& x1, const Pointf& x2, const Pointf& x,
|
||||
double tolerance);
|
||||
void ApproximateArc(LinearPathConsumer& t, const Pointf& p, const Pointf& r,
|
||||
double angle, double sweep, double tolerance);
|
||||
|
||||
struct LinearPathFilter : LinearPathConsumer {
|
||||
virtual void End();
|
||||
|
||||
LinearPathConsumer *target;
|
||||
|
||||
void PutMove(const Pointf& p) { target->Move(p); }
|
||||
void PutLine(const Pointf& p) { target->Line(p); }
|
||||
void PutEnd() { target->End(); }
|
||||
};
|
||||
|
||||
class Stroker : public LinearPathFilter {
|
||||
public:
|
||||
virtual void Move(const Pointf& p);
|
||||
virtual void Line(const Pointf& p);
|
||||
virtual void End();
|
||||
|
||||
private:
|
||||
double w2;
|
||||
double qmiter;
|
||||
double fid;
|
||||
|
||||
Pointf p0, v0, o0, a0, b0;
|
||||
Pointf p1, v1, o1, a1, b1;
|
||||
Pointf p2;
|
||||
int linecap;
|
||||
int linejoin;
|
||||
|
||||
void Finish();
|
||||
void Round(const Pointf& p, const Pointf& v1, const Pointf& v2, double r);
|
||||
void Cap(const Pointf& p0, const Pointf& v0, const Pointf& o0,
|
||||
const Pointf& a0, const Pointf& b0);
|
||||
|
||||
public:
|
||||
void Init(double width, double miterlimit, double tolerance, int linecap, int linejoin);
|
||||
};
|
||||
|
||||
class Dasher : public LinearPathFilter {
|
||||
public:
|
||||
virtual void Move(const Pointf& p);
|
||||
virtual void Line(const Pointf& p);
|
||||
|
||||
private:
|
||||
const Vector<double> *pattern;
|
||||
int patterni;
|
||||
double sum, rem;
|
||||
bool flag;
|
||||
Pointf p0;
|
||||
|
||||
void Put(const Pointf& p);
|
||||
|
||||
public:
|
||||
void Init(const Vector<double>& pattern, double distance);
|
||||
};
|
||||
|
||||
struct Transformer : public LinearPathFilter {
|
||||
public:
|
||||
virtual void Move(const Pointf& p);
|
||||
virtual void Line(const Pointf& p);
|
||||
|
||||
private:
|
||||
const Xform2D& xform;
|
||||
|
||||
public:
|
||||
Transformer(const Xform2D& xform) : xform(xform) {}
|
||||
};
|
||||
|
||||
inline RGBA Mul8(const RGBA& s, int mul)
|
||||
{
|
||||
RGBA t;
|
||||
t.r = (mul * s.r) >> 8;
|
||||
t.g = (mul * s.g) >> 8;
|
||||
t.b = (mul * s.b) >> 8;
|
||||
t.a = (mul * s.a) >> 8;
|
||||
return t;
|
||||
}
|
||||
|
||||
inline void AlphaBlend(RGBA& t, const RGBA& c)
|
||||
{
|
||||
int alpha = 256 - (c.a + (c.a >> 7));
|
||||
t.r = c.r + (alpha * t.r >> 8);
|
||||
t.g = c.g + (alpha * t.g >> 8);
|
||||
t.b = c.b + (alpha * t.b >> 8);
|
||||
t.a = c.a + (alpha * t.a >> 8);
|
||||
}
|
||||
|
||||
inline void AlphaBlendCover8(RGBA& t, const RGBA& c, int cover)
|
||||
{
|
||||
int a = c.a * cover >> 8;
|
||||
int alpha = 256 - (a + (a >> 7));
|
||||
t.r = (c.r * cover >> 8) + (alpha * t.r >> 8);
|
||||
t.g = (c.g * cover >> 8) + (alpha * t.g >> 8);
|
||||
t.b = (c.b * cover >> 8) + (alpha * t.b >> 8);
|
||||
t.a = a + (alpha * t.a >> 8);
|
||||
}
|
||||
|
||||
inline int Q8(double x)
|
||||
{
|
||||
return int(x * 256 + 0.5);
|
||||
}
|
||||
|
||||
class Rasterizer : public LinearPathConsumer {
|
||||
public:
|
||||
virtual void Move(const Pointf& p);
|
||||
virtual void Line(const Pointf& p);
|
||||
|
||||
private:
|
||||
struct Cell : Moveable<Cell> {
|
||||
int16 x;
|
||||
int16 cover;
|
||||
int area;
|
||||
|
||||
bool operator<(const Cell& b) const { return x < b.x; }
|
||||
};
|
||||
|
||||
Rectf cliprect;
|
||||
Pointf p0;
|
||||
Buffer< Vector<Cell> > cell;
|
||||
int min_y;
|
||||
int max_y;
|
||||
Size sz;
|
||||
|
||||
void Init();
|
||||
Cell *AddCells(int y, int n);
|
||||
void RenderHLine(int ey, int x1, int y1, int x2, int y2);
|
||||
void LineClip(double x1, double y1, double x2, double y2);
|
||||
int CvX(double x);
|
||||
int CvY(double y);
|
||||
void CvLine(double x1, double y1, double x2, double y2);
|
||||
bool BeginRender(int y, const Cell *&c, const Cell *&e);
|
||||
|
||||
public:
|
||||
struct Filler {
|
||||
virtual void Start(int x, int len) = 0;
|
||||
virtual void Render(int val) = 0;
|
||||
virtual void Render(int val, int len) = 0;
|
||||
};
|
||||
|
||||
void LineRaw(int x1, int y1, int x2, int y2);
|
||||
|
||||
void SetClip(const Rectf& rect);
|
||||
|
||||
int MinY() const { return min_y; }
|
||||
int MaxY() const { return max_y; }
|
||||
void Render(int y, Filler& g, bool evenodd);
|
||||
|
||||
void Reset();
|
||||
|
||||
Rasterizer(int cx, int cy);
|
||||
};
|
||||
|
||||
struct SpanSource {
|
||||
virtual void Get(RGBA *span, int x, int y, unsigned len) = 0;
|
||||
};
|
||||
|
||||
class ClipLine : NoCopy {
|
||||
byte *data;
|
||||
|
||||
public:
|
||||
void Clear() { if(!IsFull()) delete[] data; data = NULL; }
|
||||
void Set(const byte *s, int len) { data = new byte[len]; memcpy(data, s, len); }
|
||||
void SetFull() { ASSERT(!data); data = (byte *)1; }
|
||||
|
||||
bool IsEmpty() const { return !data; }
|
||||
bool IsFull() const { return data == (byte *)1; }
|
||||
operator const byte*() const { return data; }
|
||||
|
||||
ClipLine() { data = NULL; }
|
||||
~ClipLine() { Clear(); }
|
||||
};
|
||||
|
||||
Image MipMap(const Image& img);
|
||||
Image MakeMipMap(const Image& img, int level);
|
||||
|
||||
class LinearInterpolator {
|
||||
struct Dda2 {
|
||||
int count, lift, rem, mod, p;
|
||||
|
||||
void Set(int a, int b, int len);
|
||||
int Get();
|
||||
};
|
||||
|
||||
Xform2D xform;
|
||||
Dda2 ddax, dday;
|
||||
|
||||
public:
|
||||
void Set(const Xform2D& m) { xform = m; }
|
||||
|
||||
void Begin(int x, int y, int len);
|
||||
Point Get();
|
||||
};
|
||||
|
||||
class BufferPainter : public Painter {
|
||||
protected:
|
||||
virtual void ClearOp(const RGBA& color);
|
||||
|
||||
virtual void MoveOp(const Pointf& p, bool rel);
|
||||
virtual void LineOp(const Pointf& p, bool rel);
|
||||
virtual void QuadraticOp(const Pointf& p1, const Pointf& p, bool rel);
|
||||
virtual void QuadraticOp(const Pointf& p, bool rel);
|
||||
virtual void CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel);
|
||||
virtual void CubicOp(const Pointf& p2, const Pointf& p, bool rel);
|
||||
virtual void ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel);
|
||||
virtual void SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep,
|
||||
const Pointf& p, bool rel);
|
||||
virtual void CloseOp();
|
||||
virtual void DivOp();
|
||||
|
||||
virtual void FillOp(const RGBA& color);
|
||||
virtual void FillOp(const Image& image, const Xform2D& transsrc, dword flags);
|
||||
virtual void FillOp(const Pointf& p1, const RGBA& color1,
|
||||
const Pointf& p2, const RGBA& color2,
|
||||
int style);
|
||||
virtual void FillOp(const Pointf& f, const RGBA& color1,
|
||||
const Pointf& c, double r, const RGBA& color2,
|
||||
int style);
|
||||
|
||||
virtual void StrokeOp(double width, const RGBA& rgba);
|
||||
virtual void StrokeOp(double width, const Image& image, const Xform2D& transsrc,
|
||||
dword flags);
|
||||
virtual void StrokeOp(double width, const Pointf& p1, const RGBA& color1,
|
||||
const Pointf& p2, const RGBA& color2,
|
||||
int style);
|
||||
virtual void StrokeOp(double width, const Pointf& f, const RGBA& color1,
|
||||
const Pointf& c, double r, const RGBA& color2,
|
||||
int style);
|
||||
|
||||
virtual void ClipOp();
|
||||
|
||||
virtual void ColorStopOp(double pos, const RGBA& color);
|
||||
virtual void ClearStopsOp();
|
||||
|
||||
virtual void OpacityOp(double o);
|
||||
virtual void LineCapOp(int linecap);
|
||||
virtual void LineJoinOp(int linejoin);
|
||||
virtual void MiterLimitOp(double l);
|
||||
virtual void EvenOddOp(bool evenodd);
|
||||
virtual void DashOp(const Vector<double>& dash, double start);
|
||||
virtual void NoAAOp(bool noaa);
|
||||
|
||||
virtual void TransformOp(const Xform2D& m);
|
||||
|
||||
virtual void BeginOp();
|
||||
virtual void EndOp();
|
||||
|
||||
virtual void BeginMaskOp();
|
||||
|
||||
public:
|
||||
enum {
|
||||
MOVE, LINE, QUADRATIC, CUBIC, ARC, DIV
|
||||
};
|
||||
struct LinearData {
|
||||
Pointf p;
|
||||
};
|
||||
struct QuadraticData : LinearData {
|
||||
Pointf p1;
|
||||
};
|
||||
struct CubicData : QuadraticData {
|
||||
Pointf p2;
|
||||
};
|
||||
struct ArcData : LinearData {
|
||||
Pointf r;
|
||||
double angle, sweep;
|
||||
|
||||
Pointf EndPoint() const;
|
||||
};
|
||||
struct Path {
|
||||
Vector<byte> type;
|
||||
Vector<byte> data;
|
||||
};
|
||||
struct Attr : Moveable<Attr> {
|
||||
Xform2D mtx;
|
||||
double tolerance;
|
||||
bool evenodd;
|
||||
byte join;
|
||||
byte cap;
|
||||
double miter_limit;
|
||||
WithDeepCopy< Vector<double> > dash;
|
||||
WithDeepCopy< Vector<double> > stop;
|
||||
WithDeepCopy< Vector<RGBA> > stop_color;
|
||||
double dash_start;
|
||||
double opacity;
|
||||
int cliplevel;
|
||||
bool hasclip;
|
||||
bool mask;
|
||||
bool noaa;
|
||||
};
|
||||
|
||||
ImageBuffer& ib;
|
||||
|
||||
Attr attr;
|
||||
Attr pathattr;
|
||||
Array<Attr> attrstack;
|
||||
Vector< Buffer<ClipLine> > clip;
|
||||
Array< ImageBuffer > mask;
|
||||
|
||||
|
||||
Image gradient;
|
||||
RGBA gradient1, gradient2;
|
||||
int gradientn;
|
||||
|
||||
Path path;
|
||||
Pointf current, ccontrol, qcontrol, move;
|
||||
Rectf pathrect;
|
||||
|
||||
Rasterizer rasterizer;
|
||||
Buffer<RGBA> span;
|
||||
|
||||
void *PathAddRaw(int type, int size);
|
||||
template <class T> T& PathAdd(int type) { return *(T *)PathAddRaw(type, sizeof(T)); }
|
||||
|
||||
Pointf PathPoint(const Pointf& p, bool rel);
|
||||
Pointf EndPoint(const Pointf& p, bool rel);
|
||||
void DoMove0();
|
||||
void ClearPath();
|
||||
Buffer<ClipLine> RenderPath(double width, SpanSource *ss, const RGBA& color);
|
||||
void RenderImage(double width, const Image& image, const Xform2D& transsrc,
|
||||
dword flags);
|
||||
void RenderRadial(double width, const Pointf& f, const RGBA& color1,
|
||||
const Pointf& c, double r, const RGBA& color2, int style);
|
||||
void MakeGradient(RGBA color1, RGBA color2, int cx);
|
||||
void Gradient(const RGBA& color1, const RGBA& color2, const Pointf& p1, const Pointf& p2);
|
||||
void ColorStop0(Attr& a, double pos, const RGBA& color);
|
||||
void FinishMask();
|
||||
|
||||
public:
|
||||
BufferPainter(ImageBuffer& ib);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,130 +1,131 @@
|
|||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void BufferPainter::ClearPath()
|
||||
{
|
||||
path.type.Clear();
|
||||
path.data.Clear();
|
||||
current = move = Null;
|
||||
ccontrol = qcontrol = Pointf(0, 0);
|
||||
}
|
||||
|
||||
Pointf BufferPainter::PathPoint(const Pointf& p, bool rel)
|
||||
{
|
||||
Pointf r;
|
||||
r.x = IsNull(p.x) ? current.x : rel ? p.x + current.x : p.x;
|
||||
r.y = IsNull(p.y) ? current.y : rel ? p.y + current.y : p.y;
|
||||
if(IsNull(current)) {
|
||||
ClearPath();
|
||||
pathrect.left = pathrect.right = r.x;
|
||||
pathrect.top = pathrect.bottom = r.y;
|
||||
pathattr = attr;
|
||||
}
|
||||
else {
|
||||
pathrect.left = min(pathrect.left, r.x);
|
||||
pathrect.top = min(pathrect.top, r.y);
|
||||
pathrect.right = max(pathrect.right, r.x);
|
||||
pathrect.bottom = max(pathrect.bottom, r.y);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
Pointf BufferPainter::EndPoint(const Pointf& p, bool rel)
|
||||
{
|
||||
return current = PathPoint(p, rel);
|
||||
}
|
||||
|
||||
void *BufferPainter::PathAddRaw(int type, int size)
|
||||
{
|
||||
int q = path.data.GetCount();
|
||||
path.type.Add(type);
|
||||
path.data.SetCount(q + size);
|
||||
return &path.data[q];
|
||||
}
|
||||
|
||||
void BufferPainter::MoveOp(const Pointf& p, bool rel)
|
||||
{
|
||||
PathAdd<LinearData>(MOVE).p = move = ccontrol = qcontrol = EndPoint(p, rel);
|
||||
}
|
||||
|
||||
void BufferPainter::DoMove0()
|
||||
{
|
||||
if(IsNull(move))
|
||||
MoveOp(Pointf(0, 0), false);
|
||||
}
|
||||
|
||||
void BufferPainter::LineOp(const Pointf& p, bool rel)
|
||||
{
|
||||
DoMove0();
|
||||
PathAdd<LinearData>(LINE).p = ccontrol = qcontrol = EndPoint(p, rel);
|
||||
}
|
||||
|
||||
void BufferPainter::QuadraticOp(const Pointf& p1, const Pointf& p, bool rel)
|
||||
{
|
||||
DoMove0();
|
||||
QuadraticData& m = PathAdd<QuadraticData>(QUADRATIC);
|
||||
qcontrol = m.p1 = PathPoint(p1, rel);
|
||||
m.p = EndPoint(p, rel);
|
||||
}
|
||||
|
||||
void BufferPainter::QuadraticOp(const Pointf& p, bool rel)
|
||||
{
|
||||
QuadraticOp(2 * current - qcontrol, p, rel);
|
||||
}
|
||||
|
||||
void BufferPainter::CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel)
|
||||
{
|
||||
DoMove0();
|
||||
CubicData& m = PathAdd<CubicData>(CUBIC);
|
||||
m.p1 = PathPoint(p1, rel);
|
||||
ccontrol = m.p2 = PathPoint(p2, rel);
|
||||
m.p = EndPoint(p, rel);
|
||||
}
|
||||
|
||||
void BufferPainter::CubicOp(const Pointf& p2, const Pointf& p, bool rel)
|
||||
{
|
||||
CubicOp(2 * current - ccontrol, p2, p, rel);
|
||||
}
|
||||
|
||||
Pointf BufferPainter::ArcData::EndPoint() const
|
||||
{
|
||||
return r * Polar(angle + sweep) + p;
|
||||
}
|
||||
|
||||
void BufferPainter::ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel)
|
||||
{
|
||||
DoMove0();
|
||||
ArcData& m = PathAdd<ArcData>(ARC);
|
||||
m.p = PathPoint(c, rel);
|
||||
m.r = r;
|
||||
m.angle = angle;
|
||||
m.sweep = sweep;
|
||||
PathPoint(c + r, rel);
|
||||
PathPoint(c - r, rel);
|
||||
current = m.EndPoint();
|
||||
}
|
||||
|
||||
void BufferPainter::SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep,
|
||||
const Pointf& p, bool rel)
|
||||
{
|
||||
DoMove0();
|
||||
Pointf c = current;
|
||||
DoSvgArc(r, xangle, large, sweep, EndPoint(p, rel), c);
|
||||
}
|
||||
|
||||
void BufferPainter::CloseOp()
|
||||
{
|
||||
if(!IsNull(move) && current != move) {
|
||||
Line(move);
|
||||
move = Null;
|
||||
}
|
||||
}
|
||||
|
||||
void BufferPainter::DivOp()
|
||||
{
|
||||
CloseOp();
|
||||
path.type.Add(DIV);
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void BufferPainter::ClearPath()
|
||||
{
|
||||
path.type.Clear();
|
||||
path.data.Clear();
|
||||
current = move = Null;
|
||||
ccontrol = qcontrol = Pointf(0, 0);
|
||||
}
|
||||
|
||||
Pointf BufferPainter::PathPoint(const Pointf& p, bool rel)
|
||||
{
|
||||
Pointf r;
|
||||
r.x = IsNull(p.x) ? current.x : rel ? p.x + current.x : p.x;
|
||||
r.y = IsNull(p.y) ? current.y : rel ? p.y + current.y : p.y;
|
||||
if(IsNull(current)) {
|
||||
ClearPath();
|
||||
pathrect.left = pathrect.right = r.x;
|
||||
pathrect.top = pathrect.bottom = r.y;
|
||||
pathattr = attr;
|
||||
}
|
||||
else {
|
||||
pathrect.left = min(pathrect.left, r.x);
|
||||
pathrect.top = min(pathrect.top, r.y);
|
||||
pathrect.right = max(pathrect.right, r.x);
|
||||
pathrect.bottom = max(pathrect.bottom, r.y);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
Pointf BufferPainter::EndPoint(const Pointf& p, bool rel)
|
||||
{
|
||||
return current = PathPoint(p, rel);
|
||||
}
|
||||
|
||||
void *BufferPainter::PathAddRaw(int type, int size)
|
||||
{
|
||||
int q = path.data.GetCount();
|
||||
path.type.Add(type);
|
||||
path.data.SetCount(q + size);
|
||||
return &path.data[q];
|
||||
}
|
||||
|
||||
void BufferPainter::MoveOp(const Pointf& p, bool rel)
|
||||
{
|
||||
move = ccontrol = qcontrol = EndPoint(p, rel);
|
||||
PathAdd<LinearData>(MOVE).p = move;
|
||||
}
|
||||
|
||||
void BufferPainter::DoMove0()
|
||||
{
|
||||
if(IsNull(move))
|
||||
MoveOp(Pointf(0, 0), false);
|
||||
}
|
||||
|
||||
void BufferPainter::LineOp(const Pointf& p, bool rel)
|
||||
{
|
||||
DoMove0();
|
||||
PathAdd<LinearData>(LINE).p = ccontrol = qcontrol = EndPoint(p, rel);
|
||||
}
|
||||
|
||||
void BufferPainter::QuadraticOp(const Pointf& p1, const Pointf& p, bool rel)
|
||||
{
|
||||
DoMove0();
|
||||
QuadraticData& m = PathAdd<QuadraticData>(QUADRATIC);
|
||||
qcontrol = m.p1 = PathPoint(p1, rel);
|
||||
m.p = EndPoint(p, rel);
|
||||
}
|
||||
|
||||
void BufferPainter::QuadraticOp(const Pointf& p, bool rel)
|
||||
{
|
||||
QuadraticOp(2.0 * current - qcontrol, p, rel);
|
||||
}
|
||||
|
||||
void BufferPainter::CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel)
|
||||
{
|
||||
DoMove0();
|
||||
CubicData& m = PathAdd<CubicData>(CUBIC);
|
||||
m.p1 = PathPoint(p1, rel);
|
||||
ccontrol = m.p2 = PathPoint(p2, rel);
|
||||
m.p = EndPoint(p, rel);
|
||||
}
|
||||
|
||||
void BufferPainter::CubicOp(const Pointf& p2, const Pointf& p, bool rel)
|
||||
{
|
||||
CubicOp(2.0 * current - ccontrol, p2, p, rel);
|
||||
}
|
||||
|
||||
Pointf BufferPainter::ArcData::EndPoint() const
|
||||
{
|
||||
return r * Polar(angle + sweep) + p;
|
||||
}
|
||||
|
||||
void BufferPainter::ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel)
|
||||
{
|
||||
DoMove0();
|
||||
ArcData& m = PathAdd<ArcData>(ARC);
|
||||
m.p = PathPoint(c, rel);
|
||||
m.r = r;
|
||||
m.angle = angle;
|
||||
m.sweep = sweep;
|
||||
PathPoint(c + r, rel);
|
||||
PathPoint(c - r, rel);
|
||||
current = m.EndPoint();
|
||||
}
|
||||
|
||||
void BufferPainter::SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep,
|
||||
const Pointf& p, bool rel)
|
||||
{
|
||||
DoMove0();
|
||||
Pointf c = current;
|
||||
DoSvgArc(r, xangle, large, sweep, EndPoint(p, rel), c);
|
||||
}
|
||||
|
||||
void BufferPainter::CloseOp()
|
||||
{
|
||||
if(!IsNull(move) && !IsNull(current) && current != move) {
|
||||
Line(move);
|
||||
move = Null;
|
||||
}
|
||||
}
|
||||
|
||||
void BufferPainter::DivOp()
|
||||
{
|
||||
CloseOp();
|
||||
path.type.Add(DIV);
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -1,352 +1,352 @@
|
|||
#include "Painter.h"
|
||||
|
||||
// This code is based in AGG rasterizer with this original information:
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies.
|
||||
// This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// The author gratefully acknowleges the support of David Turner,
|
||||
// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
|
||||
// libray - in producing this work. See http://www.freetype.org for details.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Contact: mcseem@antigrain.com
|
||||
// mcseemagg@yahoo.com
|
||||
// http://www.antigrain.com
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#define LLOG(x) // LOG(x)
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void Rasterizer::Init()
|
||||
{
|
||||
p0 = Pointf(0, 0);
|
||||
min_y = INT_MAX;
|
||||
max_y = INT_MIN;
|
||||
}
|
||||
|
||||
void Rasterizer::Reset()
|
||||
{
|
||||
PAINTER_TIMING("Rasterizer::Reset");
|
||||
for(int i = min_y; i <= max_y; i++)
|
||||
cell[i].SetCount(0);
|
||||
Init();
|
||||
}
|
||||
|
||||
void Rasterizer::SetClip(const Rectf& rect)
|
||||
{
|
||||
cliprect = rect & Sizef(sz);
|
||||
}
|
||||
|
||||
Rasterizer::Rasterizer(int cx, int cy)
|
||||
{
|
||||
sz.cx = cx;
|
||||
sz.cy = cy;
|
||||
cell.Alloc(sz.cy + 1);
|
||||
cliprect = Sizef(sz);
|
||||
Init();
|
||||
Reset();
|
||||
}
|
||||
|
||||
inline Rasterizer::Cell *Rasterizer::AddCells(int y, int n)
|
||||
{
|
||||
Vector<Cell>& v = cell[y];
|
||||
if(v.GetAlloc() == 0) {
|
||||
v.Reserve(16);
|
||||
v.SetCount(n);
|
||||
return &v[0];
|
||||
}
|
||||
y = v.GetCount();
|
||||
v.SetCount(y + n);
|
||||
return &v[y];
|
||||
}
|
||||
|
||||
inline void Rasterizer::RenderHLine(int ey, int x1, int y1, int x2, int y2)
|
||||
{
|
||||
int ex1 = x1 >> 8;
|
||||
int ex2 = x2 >> 8;
|
||||
int fx1 = x1 & 255;
|
||||
int fx2 = x2 & 255;
|
||||
Cell *c;
|
||||
if(y1 == y2)
|
||||
return;
|
||||
int dy = y2 - y1;
|
||||
if(ex1 == ex2) {
|
||||
c = AddCells(ey, 1);
|
||||
c->x = ex1;
|
||||
c->cover = dy;
|
||||
c->area = (fx1 + fx2) * dy;
|
||||
return;
|
||||
}
|
||||
int dx = x2 - x1;
|
||||
if(dx < 0) {
|
||||
int p = fx1 * dy;
|
||||
dx = -dx;
|
||||
int delta = p / dx;
|
||||
int mod = p % dx;
|
||||
if(mod < 0) {
|
||||
delta--;
|
||||
mod += dx;
|
||||
}
|
||||
c = AddCells(ey, abs(ex2 - ex1) + 1);
|
||||
c->x = ex1;
|
||||
c->cover = delta;
|
||||
c->area = fx1 * delta;
|
||||
c++;
|
||||
ex1--;
|
||||
y1 += delta;
|
||||
if(ex1 != ex2) {
|
||||
p = (y2 - y1 + delta) * 256;
|
||||
int lift = p / dx;
|
||||
int rem = p % dx;
|
||||
if (rem < 0) {
|
||||
lift--;
|
||||
rem += dx;
|
||||
}
|
||||
mod -= dx;
|
||||
while(ex1 != ex2) {
|
||||
delta = lift;
|
||||
mod += rem;
|
||||
if(mod >= 0) {
|
||||
mod -= dx;
|
||||
delta++;
|
||||
}
|
||||
c->x = ex1;
|
||||
c->cover = delta;
|
||||
c->area = delta * 256;
|
||||
c++;
|
||||
y1 += delta;
|
||||
ex1--;
|
||||
}
|
||||
}
|
||||
c->x = ex2;
|
||||
dy = y2 - y1;
|
||||
c->cover = dy;
|
||||
c->area = (fx2 + 256) * dy;
|
||||
}
|
||||
else {
|
||||
int p = (256 - fx1) * dy;
|
||||
int delta = p / dx;
|
||||
int mod = p % dx;
|
||||
if(mod < 0) {
|
||||
delta--;
|
||||
mod += dx;
|
||||
}
|
||||
c = AddCells(ey, abs(ex2 - ex1) + 1);
|
||||
c->x = ex1;
|
||||
c->cover = delta;
|
||||
c->area = (fx1 + 256) * delta;
|
||||
c++;
|
||||
ex1++;
|
||||
y1 += delta;
|
||||
if(ex1 != ex2) {
|
||||
p = (y2 - y1 + delta) * 256;
|
||||
int lift = p / dx;
|
||||
int rem = p % dx;
|
||||
if (rem < 0) {
|
||||
lift--;
|
||||
rem += dx;
|
||||
}
|
||||
mod -= dx;
|
||||
while(ex1 != ex2) {
|
||||
delta = lift;
|
||||
mod += rem;
|
||||
if(mod >= 0) {
|
||||
mod -= dx;
|
||||
delta++;
|
||||
}
|
||||
c->x = ex1;
|
||||
c->cover = delta;
|
||||
c->area = delta * 256;
|
||||
c++;
|
||||
y1 += delta;
|
||||
ex1++;
|
||||
}
|
||||
}
|
||||
c->x = ex2;
|
||||
dy = y2 - y1;
|
||||
c->cover = dy;
|
||||
c->area = fx2 * dy;
|
||||
}
|
||||
}
|
||||
|
||||
void Rasterizer::LineRaw(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
PAINTER_TIMING("LineRaw");
|
||||
LLOG("Rasterizer::LineRaw " << x1 / 256.0 << ':' << y1 / 256.0
|
||||
<< " - " << x2 / 256.0 << ':' << y2 / 256.0);
|
||||
int ex1 = x1 >> 8;
|
||||
int ex2 = x2 >> 8;
|
||||
int ey1 = y1 >> 8;
|
||||
int ey2 = y2 >> 8;
|
||||
|
||||
ASSERT(ey1 >= 0 && ey1 <= sz.cy && ey2 >= 0 && ey2 <= sz.cy);
|
||||
|
||||
if(ey1 < min_y) {
|
||||
if(ey1 < 0) return;
|
||||
min_y = ey1;
|
||||
}
|
||||
if(ey1 > max_y) {
|
||||
if(ey1 > sz.cy) return;
|
||||
max_y = min(ey1, sz.cy - 1);
|
||||
}
|
||||
if(ey2 < min_y) {
|
||||
if(ey2 < 0) return;
|
||||
min_y = ey2;
|
||||
}
|
||||
if(ey2 > max_y) {
|
||||
if(ey2 > sz.cy) return;
|
||||
max_y = min(ey2, sz.cy - 1);
|
||||
}
|
||||
|
||||
enum dx_limit_e { dx_limit = 16384 << 8 };
|
||||
int dx = x2 - x1;
|
||||
if(dx >= dx_limit || dx <= -dx_limit) {
|
||||
int cx = (x1 + x2) >> 1;
|
||||
int cy = (y1 + y2) >> 1;
|
||||
LineRaw(x1, y1, cx, cy);
|
||||
LineRaw(cx, cy, x2, y2);
|
||||
return;
|
||||
}
|
||||
int dy = y2 - y1;
|
||||
int fy1 = y1 & 255;
|
||||
int fy2 = y2 & 255;
|
||||
|
||||
|
||||
Cell *c;
|
||||
int x_from, x_to;
|
||||
int p, rem, mod, lift, delta, first, incr;
|
||||
|
||||
if(ey1 == ey2) {
|
||||
RenderHLine(ey1, x1, fy1, x2, fy2);
|
||||
return;
|
||||
}
|
||||
incr = 1;
|
||||
if(dx == 0) {
|
||||
int ex = x1 >> 8;
|
||||
int two_fx = (x1 - (ex << 8)) << 1;
|
||||
int area;
|
||||
first = 256;
|
||||
if(dy < 0) {
|
||||
first = 0;
|
||||
incr = -1;
|
||||
}
|
||||
x_from = x1;
|
||||
delta = first - fy1;
|
||||
c = AddCells(ey1, 1);
|
||||
c->x = ex1;
|
||||
c->cover = delta;
|
||||
c->area = two_fx * delta;
|
||||
ey1 += incr;
|
||||
delta = first + first - 256;
|
||||
area = two_fx * delta;
|
||||
while(ey1 != ey2) {
|
||||
c = AddCells(ey1, 1);
|
||||
c->x = ex1;
|
||||
c->cover = delta;
|
||||
c->area = area;
|
||||
ey1 += incr;
|
||||
}
|
||||
delta = fy2 - 256 + first;
|
||||
c = AddCells(ey1, 1);
|
||||
c->x = ex1;
|
||||
c->cover = delta;
|
||||
c->area = two_fx * delta;
|
||||
return;
|
||||
}
|
||||
p = (256 - fy1) * dx;
|
||||
first = 256;
|
||||
if(dy < 0) {
|
||||
p = fy1 * dx;
|
||||
first = 0;
|
||||
incr = -1;
|
||||
dy = -dy;
|
||||
}
|
||||
delta = p / dy;
|
||||
mod = p % dy;
|
||||
if(mod < 0) {
|
||||
delta--;
|
||||
mod += dy;
|
||||
}
|
||||
x_from = x1 + delta;
|
||||
RenderHLine(ey1, x1, fy1, x_from, first);
|
||||
ey1 += incr;
|
||||
if(ey1 != ey2) {
|
||||
p = dx << 8;
|
||||
lift = p / dy;
|
||||
rem = p % dy;
|
||||
if(rem < 0) {
|
||||
lift--;
|
||||
rem += dy;
|
||||
}
|
||||
mod -= dy;
|
||||
while(ey1 != ey2) {
|
||||
delta = lift;
|
||||
mod += rem;
|
||||
if(mod >= 0) {
|
||||
mod -= dy;
|
||||
delta++;
|
||||
}
|
||||
x_to = x_from + delta;
|
||||
RenderHLine(ey1, x_from, 256 - first, x_to, first);
|
||||
x_from = x_to;
|
||||
ey1 += incr;
|
||||
}
|
||||
}
|
||||
RenderHLine(ey1, x_from, 256 - first, x2, fy2);
|
||||
}
|
||||
|
||||
void Rasterizer::Render(int y, Rasterizer::Filler& g, bool evenodd)
|
||||
{
|
||||
PAINTER_TIMING("Render");
|
||||
const Cell *c, *e;
|
||||
if(y < min_y || y > max_y) return;
|
||||
Vector<Cell>& cl = cell[y];
|
||||
if(cl.GetCount() == 0) return;
|
||||
Sort(cl);
|
||||
c = cl;
|
||||
e = cl.End();
|
||||
g.Start(c->x, (e - 1)->x);
|
||||
int cover = 0;
|
||||
while(c < e) {
|
||||
int x = c->x;
|
||||
int area = c->area;
|
||||
cover += c->cover;
|
||||
c++;
|
||||
while(c < e && c->x == x) {
|
||||
area += c->area;
|
||||
cover += c->cover;
|
||||
c++;
|
||||
}
|
||||
if(evenodd) {
|
||||
if(area) {
|
||||
int h = abs(((cover << 9) - area) >> 9) & 511;
|
||||
g.Render(h > 256 ? 512 - h : h);
|
||||
x++;
|
||||
}
|
||||
if(c < e && c->x > x) {
|
||||
int h = abs(cover) & 511;
|
||||
g.Render(h > 256 ? 512 - h : h, c->x - x);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(area) {
|
||||
g.Render(min(abs(((cover << 9) - area) >> 9), 256));
|
||||
x++;
|
||||
}
|
||||
if(c < e && c->x > x)
|
||||
g.Render(min(abs(cover), 256), c->x - x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
#include "Painter.h"
|
||||
|
||||
// This code is based in AGG rasterizer with this original information:
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies.
|
||||
// This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// The author gratefully acknowleges the support of David Turner,
|
||||
// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
|
||||
// libray - in producing this work. See http://www.freetype.org for details.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Contact: mcseem@antigrain.com
|
||||
// mcseemagg@yahoo.com
|
||||
// http://www.antigrain.com
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#define LLOG(x) // LOG(x)
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void Rasterizer::Init()
|
||||
{
|
||||
p0 = Pointf(0, 0);
|
||||
min_y = INT_MAX;
|
||||
max_y = INT_MIN;
|
||||
}
|
||||
|
||||
void Rasterizer::Reset()
|
||||
{
|
||||
PAINTER_TIMING("Rasterizer::Reset");
|
||||
for(int i = min_y; i <= max_y; i++)
|
||||
cell[i].SetCount(0);
|
||||
Init();
|
||||
}
|
||||
|
||||
void Rasterizer::SetClip(const Rectf& rect)
|
||||
{
|
||||
cliprect = rect & Sizef(sz);
|
||||
}
|
||||
|
||||
Rasterizer::Rasterizer(int cx, int cy)
|
||||
{
|
||||
sz.cx = cx;
|
||||
sz.cy = cy;
|
||||
cell.Alloc(sz.cy + 1);
|
||||
cliprect = Sizef(sz);
|
||||
Init();
|
||||
Reset();
|
||||
}
|
||||
|
||||
inline Rasterizer::Cell *Rasterizer::AddCells(int y, int n)
|
||||
{
|
||||
Vector<Cell>& v = cell[y];
|
||||
if(v.GetAlloc() == 0) {
|
||||
v.Reserve(16);
|
||||
v.SetCount(n);
|
||||
return &v[0];
|
||||
}
|
||||
y = v.GetCount();
|
||||
v.SetCount(y + n);
|
||||
return &v[y];
|
||||
}
|
||||
|
||||
inline void Rasterizer::RenderHLine(int ey, int x1, int y1, int x2, int y2)
|
||||
{
|
||||
int ex1 = x1 >> 8;
|
||||
int ex2 = x2 >> 8;
|
||||
int fx1 = x1 & 255;
|
||||
int fx2 = x2 & 255;
|
||||
Cell *c;
|
||||
if(y1 == y2)
|
||||
return;
|
||||
int dy = y2 - y1;
|
||||
if(ex1 == ex2) {
|
||||
c = AddCells(ey, 1);
|
||||
c->x = ex1;
|
||||
c->cover = dy;
|
||||
c->area = (fx1 + fx2) * dy;
|
||||
return;
|
||||
}
|
||||
int dx = x2 - x1;
|
||||
if(dx < 0) {
|
||||
int p = fx1 * dy;
|
||||
dx = -dx;
|
||||
int delta = p / dx;
|
||||
int mod = p % dx;
|
||||
if(mod < 0) {
|
||||
delta--;
|
||||
mod += dx;
|
||||
}
|
||||
c = AddCells(ey, abs(ex2 - ex1) + 1);
|
||||
c->x = ex1;
|
||||
c->cover = delta;
|
||||
c->area = fx1 * delta;
|
||||
c++;
|
||||
ex1--;
|
||||
y1 += delta;
|
||||
if(ex1 != ex2) {
|
||||
p = (y2 - y1 + delta) * 256;
|
||||
int lift = p / dx;
|
||||
int rem = p % dx;
|
||||
if (rem < 0) {
|
||||
lift--;
|
||||
rem += dx;
|
||||
}
|
||||
mod -= dx;
|
||||
while(ex1 != ex2) {
|
||||
delta = lift;
|
||||
mod += rem;
|
||||
if(mod >= 0) {
|
||||
mod -= dx;
|
||||
delta++;
|
||||
}
|
||||
c->x = ex1;
|
||||
c->cover = delta;
|
||||
c->area = delta * 256;
|
||||
c++;
|
||||
y1 += delta;
|
||||
ex1--;
|
||||
}
|
||||
}
|
||||
c->x = ex2;
|
||||
dy = y2 - y1;
|
||||
c->cover = dy;
|
||||
c->area = (fx2 + 256) * dy;
|
||||
}
|
||||
else {
|
||||
int p = (256 - fx1) * dy;
|
||||
int delta = p / dx;
|
||||
int mod = p % dx;
|
||||
if(mod < 0) {
|
||||
delta--;
|
||||
mod += dx;
|
||||
}
|
||||
c = AddCells(ey, abs(ex2 - ex1) + 1);
|
||||
c->x = ex1;
|
||||
c->cover = delta;
|
||||
c->area = (fx1 + 256) * delta;
|
||||
c++;
|
||||
ex1++;
|
||||
y1 += delta;
|
||||
if(ex1 != ex2) {
|
||||
p = (y2 - y1 + delta) * 256;
|
||||
int lift = p / dx;
|
||||
int rem = p % dx;
|
||||
if (rem < 0) {
|
||||
lift--;
|
||||
rem += dx;
|
||||
}
|
||||
mod -= dx;
|
||||
while(ex1 != ex2) {
|
||||
delta = lift;
|
||||
mod += rem;
|
||||
if(mod >= 0) {
|
||||
mod -= dx;
|
||||
delta++;
|
||||
}
|
||||
c->x = ex1;
|
||||
c->cover = delta;
|
||||
c->area = delta * 256;
|
||||
c++;
|
||||
y1 += delta;
|
||||
ex1++;
|
||||
}
|
||||
}
|
||||
c->x = ex2;
|
||||
dy = y2 - y1;
|
||||
c->cover = dy;
|
||||
c->area = fx2 * dy;
|
||||
}
|
||||
}
|
||||
|
||||
void Rasterizer::LineRaw(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
PAINTER_TIMING("LineRaw");
|
||||
LLOG("Rasterizer::LineRaw " << x1 / 256.0 << ':' << y1 / 256.0
|
||||
<< " - " << x2 / 256.0 << ':' << y2 / 256.0);
|
||||
int ex1 = x1 >> 8;
|
||||
int ex2 = x2 >> 8;
|
||||
int ey1 = y1 >> 8;
|
||||
int ey2 = y2 >> 8;
|
||||
|
||||
ASSERT(ey1 >= 0 && ey1 <= sz.cy && ey2 >= 0 && ey2 <= sz.cy);
|
||||
|
||||
if(ey1 < min_y) {
|
||||
if(ey1 < 0) return;
|
||||
min_y = ey1;
|
||||
}
|
||||
if(ey1 > max_y) {
|
||||
if(ey1 > sz.cy) return;
|
||||
max_y = min(ey1, sz.cy - 1);
|
||||
}
|
||||
if(ey2 < min_y) {
|
||||
if(ey2 < 0) return;
|
||||
min_y = ey2;
|
||||
}
|
||||
if(ey2 > max_y) {
|
||||
if(ey2 > sz.cy) return;
|
||||
max_y = min(ey2, sz.cy - 1);
|
||||
}
|
||||
|
||||
enum dx_limit_e { dx_limit = 16384 << 8 };
|
||||
int dx = x2 - x1;
|
||||
if(dx >= dx_limit || dx <= -dx_limit) {
|
||||
int cx = (x1 + x2) >> 1;
|
||||
int cy = (y1 + y2) >> 1;
|
||||
LineRaw(x1, y1, cx, cy);
|
||||
LineRaw(cx, cy, x2, y2);
|
||||
return;
|
||||
}
|
||||
int dy = y2 - y1;
|
||||
int fy1 = y1 & 255;
|
||||
int fy2 = y2 & 255;
|
||||
|
||||
|
||||
Cell *c;
|
||||
int x_from, x_to;
|
||||
int p, rem, mod, lift, delta, first, incr;
|
||||
|
||||
if(ey1 == ey2) {
|
||||
RenderHLine(ey1, x1, fy1, x2, fy2);
|
||||
return;
|
||||
}
|
||||
incr = 1;
|
||||
if(dx == 0) {
|
||||
int ex = x1 >> 8;
|
||||
int two_fx = (x1 - (ex << 8)) << 1;
|
||||
int area;
|
||||
first = 256;
|
||||
if(dy < 0) {
|
||||
first = 0;
|
||||
incr = -1;
|
||||
}
|
||||
x_from = x1;
|
||||
delta = first - fy1;
|
||||
c = AddCells(ey1, 1);
|
||||
c->x = ex1;
|
||||
c->cover = delta;
|
||||
c->area = two_fx * delta;
|
||||
ey1 += incr;
|
||||
delta = first + first - 256;
|
||||
area = two_fx * delta;
|
||||
while(ey1 != ey2) {
|
||||
c = AddCells(ey1, 1);
|
||||
c->x = ex1;
|
||||
c->cover = delta;
|
||||
c->area = area;
|
||||
ey1 += incr;
|
||||
}
|
||||
delta = fy2 - 256 + first;
|
||||
c = AddCells(ey1, 1);
|
||||
c->x = ex1;
|
||||
c->cover = delta;
|
||||
c->area = two_fx * delta;
|
||||
return;
|
||||
}
|
||||
p = (256 - fy1) * dx;
|
||||
first = 256;
|
||||
if(dy < 0) {
|
||||
p = fy1 * dx;
|
||||
first = 0;
|
||||
incr = -1;
|
||||
dy = -dy;
|
||||
}
|
||||
delta = p / dy;
|
||||
mod = p % dy;
|
||||
if(mod < 0) {
|
||||
delta--;
|
||||
mod += dy;
|
||||
}
|
||||
x_from = x1 + delta;
|
||||
RenderHLine(ey1, x1, fy1, x_from, first);
|
||||
ey1 += incr;
|
||||
if(ey1 != ey2) {
|
||||
p = dx << 8;
|
||||
lift = p / dy;
|
||||
rem = p % dy;
|
||||
if(rem < 0) {
|
||||
lift--;
|
||||
rem += dy;
|
||||
}
|
||||
mod -= dy;
|
||||
while(ey1 != ey2) {
|
||||
delta = lift;
|
||||
mod += rem;
|
||||
if(mod >= 0) {
|
||||
mod -= dy;
|
||||
delta++;
|
||||
}
|
||||
x_to = x_from + delta;
|
||||
RenderHLine(ey1, x_from, 256 - first, x_to, first);
|
||||
x_from = x_to;
|
||||
ey1 += incr;
|
||||
}
|
||||
}
|
||||
RenderHLine(ey1, x_from, 256 - first, x2, fy2);
|
||||
}
|
||||
|
||||
void Rasterizer::Render(int y, Rasterizer::Filler& g, bool evenodd)
|
||||
{
|
||||
PAINTER_TIMING("Render");
|
||||
const Cell *c, *e;
|
||||
if(y < min_y || y > max_y) return;
|
||||
Vector<Cell>& cl = cell[y];
|
||||
if(cl.GetCount() == 0) return;
|
||||
Sort(cl);
|
||||
c = cl;
|
||||
e = cl.End();
|
||||
g.Start(c->x, (e - 1)->x);
|
||||
int cover = 0;
|
||||
while(c < e) {
|
||||
int x = c->x;
|
||||
int area = c->area;
|
||||
cover += c->cover;
|
||||
c++;
|
||||
while(c < e && c->x == x) {
|
||||
area += c->area;
|
||||
cover += c->cover;
|
||||
c++;
|
||||
}
|
||||
if(evenodd) {
|
||||
if(area) {
|
||||
int h = abs(((cover << 9) - area) >> 9) & 511;
|
||||
g.Render(h > 256 ? 512 - h : h);
|
||||
x++;
|
||||
}
|
||||
if(c < e && c->x > x) {
|
||||
int h = abs(cover) & 511;
|
||||
g.Render(h > 256 ? 512 - h : h, c->x - x);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(area) {
|
||||
g.Render(min(abs(((cover << 9) - area) >> 9), 256));
|
||||
x++;
|
||||
}
|
||||
if(c < e && c->x > x)
|
||||
g.Render(min(abs(cover), 256), c->x - x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,163 +1,163 @@
|
|||
#include "Painter.h"
|
||||
#include "Fillers.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void BufferPainter::ClearOp(const RGBA& color)
|
||||
{
|
||||
UPP::Fill(~ib, color, ib.GetLength());
|
||||
}
|
||||
|
||||
Buffer<ClipLine> BufferPainter::RenderPath(double width, SpanSource *ss, const RGBA& color)
|
||||
{
|
||||
Buffer<ClipLine> newclip;
|
||||
if(width == 0)
|
||||
return newclip;
|
||||
Transformer trans(pathattr.mtx);
|
||||
trans.target = &rasterizer;
|
||||
LinearPathConsumer *g;
|
||||
Stroker stroker;
|
||||
Dasher dasher;
|
||||
bool evenodd = pathattr.evenodd;
|
||||
if(width > 0) {
|
||||
stroker.Init(width, pathattr.miter_limit, pathattr.tolerance, pathattr.cap, pathattr.join);
|
||||
stroker.target = &trans;
|
||||
if(pathattr.dash.GetCount()) {
|
||||
dasher.Init(pathattr.dash, pathattr.dash_start);
|
||||
dasher.target = &stroker;
|
||||
g = &dasher;
|
||||
}
|
||||
else
|
||||
g = &stroker;
|
||||
evenodd = false;
|
||||
}
|
||||
else {
|
||||
Close();
|
||||
g = &trans;
|
||||
}
|
||||
byte *data = path.data;
|
||||
int opacity = int(256 * pathattr.opacity);
|
||||
Pointf pos = Pointf(0, 0);
|
||||
int i = 0;
|
||||
Rasterizer::Filler *rg;
|
||||
SpanFiller span_filler;
|
||||
SolidFiller solid_filler;
|
||||
ClipFiller clip_filler(ib.GetWidth());
|
||||
NoAAFillerFilter noaa_filler;
|
||||
bool doclip = width == -2;
|
||||
if(doclip) {
|
||||
rg = &clip_filler;
|
||||
newclip.Alloc(ib.GetHeight());
|
||||
}
|
||||
else
|
||||
if(ss) {
|
||||
if(!span)
|
||||
span.Alloc(ib.GetWidth() + 1);
|
||||
span_filler.ss = ss;
|
||||
span_filler.buffer = span;
|
||||
span_filler.alpha = opacity;
|
||||
rg = &span_filler;
|
||||
}
|
||||
else {
|
||||
solid_filler.c = Mul8(color, opacity);
|
||||
rg = &solid_filler;
|
||||
}
|
||||
if(pathattr.noaa) {
|
||||
noaa_filler.Set(rg);
|
||||
rg = &noaa_filler;
|
||||
}
|
||||
for(;;) {
|
||||
if(i >= path.type.GetCount() || path.type[i] == DIV) {
|
||||
g->End();
|
||||
for(int y = rasterizer.MinY(); y <= rasterizer.MaxY(); y++) {
|
||||
solid_filler.t = span_filler.t = ib[y];
|
||||
span_filler.y = y;
|
||||
Rasterizer::Filler *rf = rg;
|
||||
MaskFillerFilter mf;
|
||||
if(clip.GetCount()) {
|
||||
const ClipLine& s = clip.Top()[y];
|
||||
if(s.IsEmpty()) goto empty;
|
||||
if(!s.IsFull()) {
|
||||
mf.Set(rg, s);
|
||||
rf = &mf;
|
||||
}
|
||||
}
|
||||
if(doclip)
|
||||
clip_filler.Clear();
|
||||
rasterizer.Render(y, *rf, evenodd);
|
||||
if(doclip)
|
||||
clip_filler.Finish(newclip[y]);
|
||||
empty:;
|
||||
}
|
||||
rasterizer.Reset();
|
||||
if(i >= path.type.GetCount())
|
||||
break;
|
||||
}
|
||||
else
|
||||
switch(path.type[i]) {
|
||||
case MOVE: {
|
||||
const LinearData *d = (LinearData *)data;
|
||||
data += sizeof(LinearData);
|
||||
g->Move(pos = d->p);
|
||||
break;
|
||||
}
|
||||
case LINE: {
|
||||
const LinearData *d = (LinearData *)data;
|
||||
data += sizeof(LinearData);
|
||||
g->Line(pos = d->p);
|
||||
break;
|
||||
}
|
||||
case QUADRATIC: {
|
||||
const QuadraticData *d = (QuadraticData *)data;
|
||||
data += sizeof(QuadraticData);
|
||||
ApproximateQuadratic(*g, pos, d->p1, d->p, pathattr.tolerance);
|
||||
pos = d->p;
|
||||
break;
|
||||
}
|
||||
case CUBIC: {
|
||||
const CubicData *d = (CubicData *)data;
|
||||
data += sizeof(CubicData);
|
||||
ApproximateCubic(*g, pos, d->p1, d->p2, d->p, pathattr.tolerance);
|
||||
pos = d->p;
|
||||
break;
|
||||
}
|
||||
case ARC: {
|
||||
const ArcData *d = (ArcData *)data;
|
||||
data += sizeof(ArcData);
|
||||
ApproximateArc(*g, d->p, d->r, d->angle, d->sweep, pathattr.tolerance);
|
||||
pos = d->EndPoint();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NEVER();
|
||||
return newclip;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
current = Null;
|
||||
return newclip;
|
||||
}
|
||||
|
||||
void BufferPainter::FillOp(const RGBA& color)
|
||||
{
|
||||
RenderPath(-1, NULL, color);
|
||||
}
|
||||
|
||||
void BufferPainter::StrokeOp(double width, const RGBA& color)
|
||||
{
|
||||
RenderPath(width, NULL, color);
|
||||
}
|
||||
|
||||
void BufferPainter::ClipOp()
|
||||
{
|
||||
Buffer<ClipLine> newclip = RenderPath(-2, NULL, RGBAZero());
|
||||
if(attr.hasclip)
|
||||
clip.Top() = newclip;
|
||||
else {
|
||||
clip.Add() = newclip;
|
||||
attr.hasclip = true;
|
||||
attr.cliplevel = clip.GetCount();
|
||||
}
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
#include "Painter.h"
|
||||
#include "Fillers.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void BufferPainter::ClearOp(const RGBA& color)
|
||||
{
|
||||
UPP::Fill(~ib, color, ib.GetLength());
|
||||
}
|
||||
|
||||
Buffer<ClipLine> BufferPainter::RenderPath(double width, SpanSource *ss, const RGBA& color)
|
||||
{
|
||||
Buffer<ClipLine> newclip;
|
||||
if(width == 0)
|
||||
return newclip;
|
||||
Transformer trans(pathattr.mtx);
|
||||
trans.target = &rasterizer;
|
||||
LinearPathConsumer *g;
|
||||
Stroker stroker;
|
||||
Dasher dasher;
|
||||
bool evenodd = pathattr.evenodd;
|
||||
if(width > 0) {
|
||||
stroker.Init(width, pathattr.miter_limit, pathattr.tolerance, pathattr.cap, pathattr.join);
|
||||
stroker.target = &trans;
|
||||
if(pathattr.dash.GetCount()) {
|
||||
dasher.Init(pathattr.dash, pathattr.dash_start);
|
||||
dasher.target = &stroker;
|
||||
g = &dasher;
|
||||
}
|
||||
else
|
||||
g = &stroker;
|
||||
evenodd = false;
|
||||
}
|
||||
else {
|
||||
Close();
|
||||
g = &trans;
|
||||
}
|
||||
byte *data = path.data;
|
||||
int opacity = int(256 * pathattr.opacity);
|
||||
Pointf pos = Pointf(0, 0);
|
||||
int i = 0;
|
||||
Rasterizer::Filler *rg;
|
||||
SpanFiller span_filler;
|
||||
SolidFiller solid_filler;
|
||||
ClipFiller clip_filler(ib.GetWidth());
|
||||
NoAAFillerFilter noaa_filler;
|
||||
bool doclip = width == -2;
|
||||
if(doclip) {
|
||||
rg = &clip_filler;
|
||||
newclip.Alloc(ib.GetHeight());
|
||||
}
|
||||
else
|
||||
if(ss) {
|
||||
if(!span)
|
||||
span.Alloc(ib.GetWidth() + 1);
|
||||
span_filler.ss = ss;
|
||||
span_filler.buffer = span;
|
||||
span_filler.alpha = opacity;
|
||||
rg = &span_filler;
|
||||
}
|
||||
else {
|
||||
solid_filler.c = Mul8(color, opacity);
|
||||
rg = &solid_filler;
|
||||
}
|
||||
if(pathattr.noaa) {
|
||||
noaa_filler.Set(rg);
|
||||
rg = &noaa_filler;
|
||||
}
|
||||
for(;;) {
|
||||
if(i >= path.type.GetCount() || path.type[i] == DIV) {
|
||||
g->End();
|
||||
for(int y = rasterizer.MinY(); y <= rasterizer.MaxY(); y++) {
|
||||
solid_filler.t = span_filler.t = ib[y];
|
||||
span_filler.y = y;
|
||||
Rasterizer::Filler *rf = rg;
|
||||
MaskFillerFilter mf;
|
||||
if(clip.GetCount()) {
|
||||
const ClipLine& s = clip.Top()[y];
|
||||
if(s.IsEmpty()) goto empty;
|
||||
if(!s.IsFull()) {
|
||||
mf.Set(rg, s);
|
||||
rf = &mf;
|
||||
}
|
||||
}
|
||||
if(doclip)
|
||||
clip_filler.Clear();
|
||||
rasterizer.Render(y, *rf, evenodd);
|
||||
if(doclip)
|
||||
clip_filler.Finish(newclip[y]);
|
||||
empty:;
|
||||
}
|
||||
rasterizer.Reset();
|
||||
if(i >= path.type.GetCount())
|
||||
break;
|
||||
}
|
||||
else
|
||||
switch(path.type[i]) {
|
||||
case MOVE: {
|
||||
const LinearData *d = (LinearData *)data;
|
||||
data += sizeof(LinearData);
|
||||
g->Move(pos = d->p);
|
||||
break;
|
||||
}
|
||||
case LINE: {
|
||||
const LinearData *d = (LinearData *)data;
|
||||
data += sizeof(LinearData);
|
||||
g->Line(pos = d->p);
|
||||
break;
|
||||
}
|
||||
case QUADRATIC: {
|
||||
const QuadraticData *d = (QuadraticData *)data;
|
||||
data += sizeof(QuadraticData);
|
||||
ApproximateQuadratic(*g, pos, d->p1, d->p, pathattr.tolerance);
|
||||
pos = d->p;
|
||||
break;
|
||||
}
|
||||
case CUBIC: {
|
||||
const CubicData *d = (CubicData *)data;
|
||||
data += sizeof(CubicData);
|
||||
ApproximateCubic(*g, pos, d->p1, d->p2, d->p, pathattr.tolerance);
|
||||
pos = d->p;
|
||||
break;
|
||||
}
|
||||
case ARC: {
|
||||
const ArcData *d = (ArcData *)data;
|
||||
data += sizeof(ArcData);
|
||||
ApproximateArc(*g, d->p, d->r, d->angle, d->sweep, pathattr.tolerance);
|
||||
pos = d->EndPoint();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NEVER();
|
||||
return newclip;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
current = Null;
|
||||
return newclip;
|
||||
}
|
||||
|
||||
void BufferPainter::FillOp(const RGBA& color)
|
||||
{
|
||||
RenderPath(-1, NULL, color);
|
||||
}
|
||||
|
||||
void BufferPainter::StrokeOp(double width, const RGBA& color)
|
||||
{
|
||||
RenderPath(width, NULL, color);
|
||||
}
|
||||
|
||||
void BufferPainter::ClipOp()
|
||||
{
|
||||
Buffer<ClipLine> newclip = RenderPath(-2, NULL, RGBAZero());
|
||||
if(attr.hasclip)
|
||||
clip.Top() = newclip;
|
||||
else {
|
||||
clip.Add() = newclip;
|
||||
attr.hasclip = true;
|
||||
attr.cliplevel = clip.GetCount();
|
||||
}
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue