ultimatepp/uppsrc/Painter/Fillers.cpp
mirek-fidler 2d0f19053a
Painter2 (#182)
Painter improvements: Multithreaded rendering improved, new image filter (like Lanczos 3) option, image mapping is now more precise
2023-12-24 15:21:23 +01:00

461 lines
No EOL
7.4 KiB
C++

#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);
}
}