ultimatepp/uppsrc/Painter/Fill.cpp
cxl c32d6a511a Painter: fixed stroke bug
git-svn-id: svn://ultimatepp.org/upp/trunk@783 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2009-01-18 12:18:30 +00:00

210 lines
5.6 KiB
C++

#include "Painter.h"
NAMESPACE_UPP
void BufferPainter::FillOp(const RGBA& c)
{
if(inpath)
path.close_polygon();
pixf.noaa = pathattr.noaa;
RGBA color = c;
if(PathVisible(0) && color.a) {
if(pathattr.opacity != 1.0) {
color.a = int(color.a * pathattr.opacity);
color.r = int(color.r * pathattr.opacity);
color.g = int(color.g * pathattr.opacity);
color.b = int(color.b * pathattr.opacity);
}
if(color.a) {
rasterizer.reset();
rasterizer.filling_rule(pathattr.evenodd ? agg::fill_even_odd : agg::fill_non_zero);
rasterizer.add_path(curved_trans);
if(clip.GetCount()) {
agg::rendering_buffer mask_rbuf;
mask_rbuf.attach(~clip.Top(), size.cx, size.cy, size.cx);
agg::alpha_mask_gray8 mask(mask_rbuf);
agg::scanline_u8_am<agg::alpha_mask_gray8> sl(mask);
renderer.color(color);
agg::render_scanlines(rasterizer, sl, renderer);
}
else {
renderer.color(*(color_type *)&color);
agg::render_scanlines(rasterizer, scanline_p, renderer);
}
rasterizer.reset();
}
}
inpath = false;
}
struct UppImageAggSpan {
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;
}
};
agg::span_interpolator_linear<> interpolator;
int ax, ay, cx, cy, maxx, maxy;
byte style;
byte hstyle, vstyle;
bool fast;
bool fixed;
const RGBA *image;
int alpha;
void SetImage(const Image& img) {
image = ~img;
cx = img.GetWidth();
cy = img.GetHeight();
maxx = cx - 1;
maxy = cy - 1;
ax = 6000000 / cx * cx;
ay = 6000000 / cy * cy;
}
RGBA Pixel(int x, int y) { return image[cx * 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[cx * y + x] : RGBAZero();
}
void prepare() {}
void generate(RGBA *_span, int x, int y, unsigned len)
{
interpolator.begin(x + 0.5, y + 0.5, len);
RGBA *span = (RGBA *)_span;
fixed = hstyle && vstyle;
while(len--) {
int x_hr;
int y_hr;
interpolator.coordinates(&x_hr, &y_hr);
x_hr -= 128;
y_hr -= 128;
int x_lr = x_hr >> 8;
int y_lr = y_hr >> 8;
if(hstyle == FILL_HREPEAT)
x_lr = (x_lr + ax) % cx;
if(vstyle == FILL_VREPEAT)
y_lr = (y_lr + ay) % cy;
if(fast) {
RGBA v;
if(x_lr > 0 && x_lr < maxx && y_lr > 0 && y_lr < maxy)
v = Pixel(x_lr, y_lr);
if(style == 0 && (x_lr < -1 || x_lr > cx || y_lr < -1 || y_lr > cy))
v == RGBAZero();
else
v = GetPixel(x_lr, y_lr);
if(alpha == 256)
*span = v;
else {
span->r = byte((alpha * v.r) >> 8);
span->g = byte((alpha * v.g) >> 8);
span->b = byte((alpha * v.b) >> 8);
span->a = byte((alpha * v.a) >> 8);
}
}
else {
RGBAV v;
v.Set(256 * 256 / 2);
x_hr &= 255;
y_hr &= 255;
if(x_lr > 0 && x_lr < maxx && y_lr > 0 && y_lr < maxy) {
v.Put((256 - x_hr) * (256 - y_hr), Pixel(x_lr, y_lr));
v.Put(x_hr * (256 - y_hr), Pixel(x_lr + 1, y_lr));
v.Put((256 - x_hr) * y_hr, Pixel(x_lr, y_lr + 1));
v.Put(x_hr * y_hr, Pixel(x_lr + 1, y_lr + 1));
}
else
if(style == 0 && (x_lr < -1 || x_lr > cx || y_lr < -1 || y_lr > cy))
v.Set(0);
else {
v.Put((256 - x_hr) * (256 - y_hr), GetPixel(x_lr, y_lr));
v.Put(x_hr * (256 - y_hr), GetPixel(x_lr + 1, y_lr));
v.Put((256 - x_hr) * y_hr, GetPixel(x_lr, y_lr + 1));
v.Put(x_hr * y_hr, GetPixel(x_lr + 1, y_lr + 1));
}
v.r >>= 16;
v.g >>= 16;
v.b >>= 16;
v.a >>= 16;
if(alpha == 256) {
span->r = (byte)v.r;
span->g = (byte)v.g;
span->b = (byte)v.b;
span->a = (byte)v.a;
}
else {
span->r = byte((alpha * v.r) >> 8);
span->g = byte((alpha * v.g) >> 8);
span->b = byte((alpha * v.b) >> 8);
span->a = byte((alpha * v.a) >> 8);
}
}
++span;
++interpolator;
}
}
};
void BufferPainter::FillOp(const Image& image, const Matrix2D& transsrc, dword flags)
{
if(image.GetWidth() == 0 || image.GetHeight() == 0)
return;
if(inpath)
path.close_polygon();
span_alloc sa;
pixf.noaa = pathattr.noaa;
Matrix2D m = transsrc * pathattr.mtx;
m.invert();
UppImageAggSpan sg;
sg.interpolator.transformer(m);
sg.alpha = int(pathattr.opacity * 256);
sg.SetImage(image);
sg.style = flags & 15;
sg.hstyle = flags & 3;
sg.vstyle = flags & 12;
sg.fast = flags & FILL_FAST;
rasterizer.reset();
rasterizer.filling_rule(pathattr.evenodd ? agg::fill_even_odd : agg::fill_non_zero);
rasterizer.add_path(curved_trans);
if(clip.GetCount()) {
agg::rendering_buffer mask_rbuf;
mask_rbuf.attach(~clip.Top(), size.cx, size.cy, size.cx);
agg::alpha_mask_gray8 mask(mask_rbuf);
agg::scanline_u8_am<agg::alpha_mask_gray8> sl(mask);
agg::render_scanlines_aa(rasterizer, sl, renb, sa, sg);
}
else
agg::render_scanlines_aa(rasterizer, scanline_p, renb, sa, sg);
rasterizer.reset();
inpath = false;
}
END_UPP_NAMESPACE