Painter 2.0 clipping

git-svn-id: svn://ultimatepp.org/upp/trunk@852 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2009-02-12 11:14:23 +00:00
parent 7865e5bcd2
commit 64994ce5aa
9 changed files with 204 additions and 160 deletions

View file

@ -154,7 +154,7 @@ private:
bool BeginRender(int y, const Cell *&c, const Cell *&e);
public:
struct Target {
struct Filler {
virtual void Start(int x, int len) = 0;
virtual void Render(int val) = 0;
virtual void Render(int val, int len) = 0;
@ -166,29 +166,18 @@ public:
int MinY() const { return min_y; }
int MaxY() const { return max_y; }
void Render(int y, Target& g, bool evenodd);
void Render(int y, Filler& g, bool evenodd);
void Reset();
Rasterizer(int cx, int cy);
};
struct ScanLine {
int xmin, xmax;
Buffer<byte> data;
int datalen;
bool IsFull();
bool IsEmpty();
String ToString() const;
};
struct SpanSource {
virtual void Get(RGBA *span, int x, int y, unsigned len) = 0;
};
struct SolidFiller : Rasterizer::Target {
struct SolidFiller : Rasterizer::Filler {
RGBA *t;
RGBA c;
@ -197,7 +186,7 @@ struct SolidFiller : Rasterizer::Target {
void Render(int val, int len);
};
struct SpanFiller : Rasterizer::Target {
struct SpanFiller : Rasterizer::Filler {
RGBA *t;
const RGBA *s;
int y;
@ -210,24 +199,54 @@ struct SpanFiller : Rasterizer::Target {
void Render(int val, int len);
};
struct RecFiller : Rasterizer::Target {
class ClipLine {
byte *data;
public:
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() { if(!IsFull()) delete[] data; }
};
struct ClipFiller : Rasterizer::Filler {
Buffer<byte> buffer;
byte *t;
int x;
int maxx;
int maxlen;
int cx;
int last;
byte *lastn;
bool empty;
bool full;
void Span(int c, int len);
virtual void Render(int val);
virtual void Render(int val, int len);
virtual void Start(int x, int len);
void Finish();
void GetResult(Buffer<byte>& tgt, int& maxx, int& maxlen);
void Clear();
void Finish(ClipLine& cl);
RecFiller(int cx);
ClipFiller(int cx);
};
struct MaskFillerFilter : Rasterizer::Filler {
Rasterizer::Filler *t;
const byte *mask;
int empty;
int full;
void Start(int minx, int maxx);
void Render(int val, int len);
void Render(int val);
void Set(Rasterizer::Filler *f, const byte *m) { t = f; mask = m; empty = full = 0; }
};
Image MipMap(const Image& img);
@ -345,9 +364,14 @@ public:
ImageBuffer& ib;
Attr attr;
Attr pathattr;
Array<Attr> attrstack;
Attr attr;
Attr pathattr;
Array<Attr> attrstack;
Vector< Buffer<ClipLine> > clip;
Image gradient;
RGBA gradient1, gradient2;
int gradientn;
Path path;
Pointf current, ccontrol, qcontrol, move;
@ -359,17 +383,18 @@ public:
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();
void RenderPath(double width, SpanSource *ss, const RGBA& color);
void RenderImage(double width, const Image& image, const Xform2D& transsrc, dword flags);
void RenderRadial(double width, const Pointf& f, const RGBA& color1,
const Pointf& c, double r, const RGBA& color2, int style);
void MakeGradient(RGBA *t, RGBA color1, RGBA color2, int cx);
Image GetGradient(const RGBA& color1, const RGBA& color2, const Pointf& p1, const Pointf& p2);
void ColorStop0(Attr& a, double pos, const RGBA& color);
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);
public:
BufferPainter(ImageBuffer& ib);

View file

@ -16,8 +16,8 @@ void BufferPainter::EndOp()
}
pathattr = attr = attrstack.Top();
attrstack.Drop();
#if 0
clip.SetCount(attr.cliplevel);
#if 0
if(attr.mask)
FinishMask();
#endif
@ -126,6 +126,8 @@ BufferPainter::BufferPainter(ImageBuffer& ib)
attr.mask = false;
attr.noaa = false;
pathattr = attr;
gradientn = Null;
}
END_UPP_NAMESPACE

View file

@ -2,19 +2,26 @@
NAMESPACE_UPP
void BufferPainter::MakeGradient(RGBA *t, RGBA color1, RGBA color2, int cx)
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] * (cx - 1));
h = (int)(pathattr.stop[i] * (n - 1));
ch = pathattr.stop_color[i];
}
else {
h = cx - 1;
h = n - 1;
ch = color2;
}
int w = h - l;
@ -29,19 +36,18 @@ void BufferPainter::MakeGradient(RGBA *t, RGBA color1, RGBA color2, int cx)
l = h;
}
*t = cl;
gradient = ib;
}
Image BufferPainter::GetGradient(const RGBA& color1, const RGBA& color2, const Pointf& p1, const Pointf& p2)
void BufferPainter::Gradient(const RGBA& color1, const RGBA& color2, const Pointf& p1, const Pointf& p2)
{
int n = minmax(int(Distance(p1, p2) * pathattr.mtx.GetScale()), 2, 4096);
ImageBuffer ib(n, 1);
MakeGradient(ib, color1, color2, n);
return ib;
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)
{
Fill(GetGradient(color1, color2, p1, p2), p1, p2,
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));
@ -49,7 +55,8 @@ void BufferPainter::FillOp(const Pointf& p1, const RGBA& color1, const Pointf& p
void BufferPainter::StrokeOp(double width, const Pointf& p1, const RGBA& color1, const Pointf& p2, const RGBA& color2, int style)
{
Stroke(width, GetGradient(color1, color2, p1, p2), p1, p2,
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));

View file

@ -2,115 +2,96 @@
NAMESPACE_UPP
RecFiller::RecFiller(int _cx)
ClipFiller::ClipFiller(int _cx)
{
cx = _cx;
buffer.Alloc(2 * cx + 2);
}
void RecFiller::Start(int xmin, int xmax)
void ClipFiller::Clear()
{
t = ~buffer;
x = 0;
maxlen = 0;
maxx = 0;
empty = true;
full = true;
last = -1;
}
void ClipFiller::Start(int xmin, int xmax)
{
Render(0, xmin);
}
void RecFiller::Render(int val)
void ClipFiller::Span(int val, int len)
{
Render(val, 1); //!Optimize later!
/*
if(val == 0) {
*t++ = 0;
*t++ = 0;
int v = val >> 1;
if(last == val) {
int n = min(v + 128 - *lastn - 1, len);
*lastn += n;
len -= n;
}
else
if(val == 256) {
*t++ = 0;
*t++ = 128;
}
else
*t++ = val;
x++;
*/
}
void RecFiller::Span(int c, int len)
{
last = -1;
while(len > 128) {
int n = min(len, 128);
*t++ = 0;
*t++ = c + n - 1;
*t++ = v + n - 1;
len -= n;
}
if(len) {
*t++ = 0;
*t++ = c + len - 1;
last = val;
lastn = t;
*t++ = v + len - 1;
}
}
void RecFiller::Render(int val, int len)
void ClipFiller::Render(int val, int len)
{
DLOG(val << " " << len);
if(val == 256) {
Span(128, len);
if(len > maxlen) {
maxx = x;
maxlen = len;
}
Span(256, len);
empty = false;
}
else
if(val == 0)
Span(0, len);
else {
memset(t, val, len);
t += len;
full = false;
if(val == 0)
Span(0, len);
else {
memset(t, val, len);
t += len;
empty = false;
last = -1;
}
}
x += len;
}
void RecFiller::Finish()
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 RecFiller::GetResult(Buffer<byte>& tgt, int& _maxx, int& _maxlen)
void MaskFillerFilter::Render(int val)
{
tgt.Clear();
int l = t - ~buffer;
tgt.Alloc(l);
memcpy(~tgt, ~buffer, l);
_maxx = maxx;
_maxlen = maxlen;
LOGHEXDUMP(~tgt, l);
DDUMP(maxx);
DDUMP(maxlen);
}
struct RasterizerMaskFilter : Rasterizer::Target {
Rasterizer::Target *t;
byte *mask;
int empty;
int full;
void Start(int minx, int maxx);
void Render(int val, int len);
void Render(int val);
RasterizerMaskFilter() { empty = full = 0; }
};
void RasterizerMaskFilter::Render(int val)
{
Render(val, 1);
/* for(;;) {
for(;;) {
if(empty) {
f.t++;
t->Render(0);
empty--;
return;
}
@ -124,17 +105,15 @@ void RasterizerMaskFilter::Render(int val)
t->Render(val * m >> 8);
return;
}
else {
if(m < 128)
empty = m + 1;
else
full = m - 128 + 1;
}
m = *mask++;
if(m < 128)
empty = m + 1;
else
full = m - 128 + 1;
}
*/
}
void RasterizerMaskFilter::Render(int val, int len)
void MaskFillerFilter::Render(int val, int len)
{
while(len)
if(empty) {
@ -146,21 +125,19 @@ void RasterizerMaskFilter::Render(int val, int len)
else
if(full) {
int n = min(len, full);
t->Render(256, n);
t->Render(val, n);
full -= n;
len -= n;
empty = false;
}
else {
byte m = *mask++;
if(m) {
int r = val * m >> 8;
if(r)
empty = false;
t->Render(r);
len--;
}
else {
m = *mask++;
if(m < 128)
empty = m + 1;
else
@ -169,17 +146,17 @@ void RasterizerMaskFilter::Render(int val, int len)
}
}
struct RasterizerNil : Rasterizer::Target {
struct NilFiller : Rasterizer::Filler {
void Start(int minx, int maxx) {}
void Render(int val, int len) {}
void Render(int val) {}
};
void RasterizerMaskFilter::Start(int minx, int maxx)
void MaskFillerFilter::Start(int minx, int maxx)
{
t->Start(minx, maxx);
Rasterizer::Target *h = t;
RasterizerNil nil;
Rasterizer::Filler *h = t;
NilFiller nil;
t = &nil;
Render(0, minx);
t = h;

View file

@ -127,7 +127,7 @@ struct PainterRadialSpan : SpanSource {
int cx, cy, r, fx, fy;
int style;
int alpha;
RGBA gradient[2048];
const RGBA *gradient;
bool focus;
double C;
@ -201,7 +201,8 @@ void BufferPainter::RenderRadial(double width, const Pointf& f, const RGBA& colo
sg.interpolator.Set(Inverse(pathattr.mtx));
sg.style = style;
sg.Set((int)c.x, (int)c.y, (int)r, (int)f.x, (int)f.y);
MakeGradient(sg.gradient, color1, color2, 2048);
MakeGradient(color1, color2, 2048);
sg.gradient = gradient[0];
RenderPath(width, &sg, RGBAZero());
}

View file

@ -282,7 +282,7 @@ void Rasterizer::LineRaw(int x1, int y1, int x2, int y2)
RenderHLine(ey1, x_from, 256 - first, x2, fy2);
}
void Rasterizer::Render(int y, Target& g, bool evenodd)
void Rasterizer::Render(int y, Rasterizer::Filler& g, bool evenodd)
{
PAINTER_TIMING("Render");
const Cell *c, *e;

View file

@ -7,10 +7,11 @@ void BufferPainter::ClearOp(const RGBA& color)
UPP::Fill(~ib, color, ib.GetLength());
}
void BufferPainter::RenderPath(double width, SpanSource *ss, const RGBA& color)
Buffer<ClipLine> BufferPainter::RenderPath(double width, SpanSource *ss, const RGBA& color)
{
Buffer<ClipLine> newclip;
if(width == 0)
return;
return newclip;
Transformer trans(pathattr.mtx);
trans.target = &rasterizer;
LinearPathConsumer *g;
@ -37,13 +38,14 @@ void BufferPainter::RenderPath(double width, SpanSource *ss, const RGBA& color)
int opacity = int(256 * pathattr.opacity);
Pointf pos = Pointf(0, 0);
int i = 0;
Rasterizer::Target *rg;
Rasterizer::Filler *rg;
SpanFiller span_filler;
SolidFiller solid_filler;
RecFiller record_filler(ib.GetWidth());
bool clip = width == -2;
if(clip) {
rg = &record_filler;
ClipFiller clip_filler(ib.GetWidth());
bool doclip = width == -2;
if(doclip) {
rg = &clip_filler;
newclip.Alloc(ib.GetHeight());
}
else
if(ss) {
@ -58,19 +60,29 @@ void BufferPainter::RenderPath(double width, SpanSource *ss, const RGBA& color)
solid_filler.c = Mul8(color, opacity);
rg = &solid_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.Render(y, *rg, evenodd);
if(clip) {
record_filler.Finish();
Buffer<byte> h;
int maxx, maxlen;
record_filler.GetResult(h, maxx, maxlen);
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())
@ -113,11 +125,12 @@ void BufferPainter::RenderPath(double width, SpanSource *ss, const RGBA& color)
}
default:
NEVER();
return;
return newclip;
}
i++;
}
current = Null;
return newclip;
}
void BufferPainter::FillOp(const RGBA& color)
@ -132,7 +145,14 @@ void BufferPainter::StrokeOp(double width, const RGBA& color)
void BufferPainter::ClipOp()
{
RenderPath(-2, NULL, RGBAZero());
Buffer<ClipLine> newclip = RenderPath(-2, NULL, RGBAZero());
if(attr.hasclip)
clip.Top() = newclip;
else {
clip.Add() = newclip;
attr.hasclip = true;
attr.cliplevel = clip.GetCount();
}
}
END_UPP_NAMESPACE

View file

@ -2,8 +2,6 @@
void ClippingExample(Painter& sw)
{
sw.Rectangle(0, 0, 100000, 100000).Clip();
Font fnt = Roman(150).Bold();
String txt = "CLIPPED!";
Size tsz = GetTextSize(txt, fnt);
@ -12,8 +10,32 @@ void ClippingExample(Painter& sw)
sw.Text(0, 0, txt, fnt).Fill(Green());
sw.End();
sw.Text(0, 0, txt, fnt).Stroke(0.5, Black());
}
void NoClippingExample(Painter& sw)
{
Font fnt = Roman(150).Bold();
String txt = "CLIPPED!";
Size tsz = GetTextSize(txt, fnt);
sw.Text(0, 0, txt, fnt).Fill(Green());
sw.Text(0, 0, txt, fnt).Stroke(0.5, Black());
}
void ClippingExample2(Painter& sw)
{
sw.Begin();
sw.Ellipse(200, 200, 200, 200).Stroke(2, Red()).Clip();
sw.Begin();
sw.Ellipse(200, 200, 100, 300).Clip().Stroke(2, Red());
sw.Text(0, 0, "CL", Arial(360).Bold()).Fill(Blue());
sw.End();
sw.Text(0, 0, "CL", Arial(360).Bold()).Opacity(0.4).Fill(Black());
sw.End();
}
INITBLOCK {
RegisterExample("Clipping", ClippingExample);
RegisterExample("Clipping removed (to benchmark) ", NoClippingExample);
RegisterExample("Clipping 2", ClippingExample2);
}

View file

@ -6,18 +6,8 @@ void TextFillGradient(Painter& sw)
Font fnt = Arial(100).Bold().Italic();
Size tsz = GetTextSize(txt, fnt);
sw.Text(100, 100, txt, fnt)
.Fill(100, 100, Blue(), 100 + tsz.cx, 100/* + tsz.cy*/, LtRed());
.Fill(100, 100, Blue(), 100 + tsz.cx, 100 + tsz.cy, LtRed());
sw.Translate(0, 200);
sw.Rectangle(100, 100, tsz.cx, tsz.cy)
.Stroke(1, Blue())
.Fill(TestImg::test(), 100, 100, 100 + tsz.cx, 100 + tsz.cy);
sw.Move(100, 300).RelLine(tsz.cx + 50, 0).RelLine(-30, tsz.cy).RelLine(-tsz.cx / 2, 0)
.Fill(100, 300, Blue(), 100 + tsz.cx, 300/* + tsz.cy*/, LtRed())
// .Fill(TestImg::test(), 100, 300, 100 + tsz.cx, 300 + tsz.cy)
.Stroke(1, Blue());
/* sw.Text(100, 100, txt, fnt)
.Fill(TestImg::test(), 100, 100, 100 + tsz.cx, 100 + tsz.cy)
.Stroke(1, Black());*/
}
INITBLOCK {