#include "Painter.h" #include "Fillers.h" #include "AlphaBlend.h" namespace Upp { void SolidFiller::Start(int minx, int maxx) { t += minx; } inline RGBA InvertRGBA(const RGBA& c) { RGBA a; a.r = ~c.r; a.g = ~c.g; a.b = ~c.b; a.a = 255; return a; } void SolidFiller::Render(int val) { AlphaBlend(t, invert ? InvertRGBA(*t) : c, val); t++; } void SolidFiller::Render(int val, int len) { if(val == 0) { t += len; return; } if(invert) { RGBA *e = t + len; if(val == 256) while(t < e) { *t = InvertRGBA(*t); t++; } else while(t < e) { AlphaBlend(t, InvertRGBA(*t), val); t++; } } else { if(((val - 256) | (c.a - 255)) == 0) Fill(t, c, len); else AlphaBlend(t, c, val, len); t += len; } } void SubpixelFiller::Start(int minx, int maxx) { int x = minx / 3; if(x > 0) { begin = sbuffer; x--; } else begin = sbuffer + 3; t += x; sbuffer[0] = sbuffer[1] = sbuffer[2] = sbuffer[3] = sbuffer[4] = sbuffer[5] = sbuffer[6] = sbuffer[7] = 0; v = sbuffer + 3 + minx % 3; if(ss) { int xx = maxx / 3; ss->Get(buffer, x, y, xx - x + 2); s = buffer; } } void SubpixelFiller::Render(int val) { int16 *w = v; int h = val / 9; int h2 = h + h; w[-2] += h; w[2] += h; w[-1] += h2; w[1] += h2; w[0] += val - h2 - h2 - h2; w[3] = 0; v++; } void SubpixelFiller::RenderN(int val, int h, int n) { int16 *w = v; int h2 = h + h; int hv2 = val - h2 - h2; int h3 = h2 + h; int hh; v += n; switch(n) { case 1: w[-2] += h; w[-1] += h2; w[1] += h2; w[0] += hv2 - h2; w[2] += h; w[3] = 0; break; case 2: w[-2] += h; w[3] = h; w[-1] += h3; w[2] += h3; w[0] += hv2; w[1] += hv2; w[4] = 0; break; case 3: w[-2] += h; w[4] = h; w[-1] += h3; w[3] = h3; hh = hv2 + h; w[0] += hh; w[2] += hh; w[1] += hv2 + h2; w[5] = 0; break; case 4: w[-2] += h; w[5] = h; w[-1] += h3; w[4] = h3; hh = hv2 + h; w[0] += hh; w[3] = hh; hh = hv2 + h3; w[1] += hh; w[2] += hh; w[6] = 0; break; case 5: w[-2] += h; w[6] = h; w[-1] += h3; w[5] = h3; hh = hv2 + h; w[0] += hh; w[4] = hh; hh = h3 + hv2; w[1] += hh; w[3] = hh; w[2] += h3 + hv2 + h; w[7] = 0; break; case 6: w[-2] += h; w[7] = h; w[-1] += h3; w[6] = h3; hh = hv2 + h; w[0] += hh; w[5] = hh; hh = h3 + hv2; w[1] += hh; w[4] = hh; hh = h3 + hv2 + h; w[2] += hh; w[3] = hh; w[8] = 0; break; } } void SubpixelFiller::Render(int val, int len) { int h = val / 9; if(len > 6) { int q = (3333333 - (v + 2 - begin)) % 3; len -= q + 2; int l = int(v + 2 + q - begin); RenderN(val, h, q + 4); Write(l / 3); l = len / 3; len -= 3 * l; RGBA *e = min(t + l, end); if(invert && !ss) { if(val == 256) while(t < e) { *t = InvertRGBA(*t); t++; } else while(t < e) { AlphaBlend(t, InvertRGBA(*t), val); t++; } } else { if(val == 256) if(!ss && color.a == 255) { Fill(t, color, int(e - t)); t = e; } else while(t < e) AlphaBlend(t++, ss ? Mul8(*s++, alpha) : color); else if(ss) while(t < e) AlphaBlend(t++, Mul8(*s++, alpha), val); else { RGBA c = Mul8(color, val); while(t < e) AlphaBlend(t++, c); } } v = begin = sbuffer + 3; v[0] = h + h + h; v[1] = h; v[2] = 0; } RenderN(val, h, len); } void SubpixelFiller::Write(int len) { RGBA *e = min(t + len, end); int16 *q = begin; while(t < e) { RGBA c = ss ? Mul8(*s++, alpha) : invert ? InvertRGBA(*t) : color; int a; if(t->a != 255) AlphaBlend(t, c, (q[0] + q[1] + q[2]) / 3); else if(c.a == 255) { t->r = (c.r * q[0] >> 8) + ((257 - q[0]) * t->r >> 8); t->g = (c.g * q[1] >> 8) + ((257 - q[1]) * t->g >> 8); t->b = (c.b * q[2] >> 8) + ((257 - q[2]) * t->b >> 8); } else { a = c.a * q[0] >> 8; t->r = (c.r * q[0] >> 8) + ((256 - a - (a >> 7)) * t->r >> 8); a = c.a * q[1] >> 8; t->g = (c.g * q[1] >> 8) + ((256 - a - (a >> 7)) * t->g >> 8); a = c.a * q[2] >> 8; t->b = (c.b * q[2] >> 8) + ((256 - a - (a >> 7)) * t->b >> 8); } t++; q += 3; } } void SubpixelFiller::End() { v[3] = v[4] = v[5] = 0; Write(int(v + 3 - begin) / 3); } 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; AlphaBlend(t++, *s++, val); } void SpanFiller::Render(int val, int len) { if(val == 0) { t += len; s += len; return; } if(alpha != 256) val = alpha * val >> 8; AlphaBlend(t, s, val, len); t += len; s += len; } void ClipFiller::Init(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(ClippingLine& cl) { if(empty) return; while(x < cx) { int n = min(cx - x, 128); *t++ = 0; *t++ = n - 1; x += n; full = false; } ASSERT(t - ~buffer <= 2 * cx); if(full) cl.SetFull(); else cl.Set(~buffer, int(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); } }