Fixed rounding problem in subpixel rendering

git-svn-id: svn://ultimatepp.org/upp/trunk@899 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2009-02-23 17:49:45 +00:00
parent daf2cece0d
commit e16d4ea2da
6 changed files with 48 additions and 39 deletions

View file

@ -128,10 +128,9 @@ void SubpixelFiller::Render(int val)
v++; v++;
} }
void SubpixelFiller::RenderN(int val, int n) void SubpixelFiller::RenderN(int val, int h, int n)
{ {
int16 *w = v; int16 *w = v;
int h = val / 9;
int h2 = h + h; int h2 = h + h;
int hv2 = val - h2 - h2; int hv2 = val - h2 - h2;
int h3 = h2 + h; int h3 = h2 + h;
@ -214,11 +213,12 @@ void SubpixelFiller::RenderN(int val, int n)
void SubpixelFiller::Render(int val, int len) void SubpixelFiller::Render(int val, int len)
{ {
int h = val / 9;
if(len > 6) { if(len > 6) {
int q = (3333333 - (v + 2 - begin)) % 3; int q = (3333333 - (v + 2 - begin)) % 3;
len -= q + 2; len -= q + 2;
int l = v + 2 + q - begin; int l = v + 2 + q - begin;
RenderN(val, q + 4); RenderN(val, h, q + 4);
Write(l / 3); Write(l / 3);
l = len / 3; l = len / 3;
len -= 3 * l; len -= 3 * l;
@ -235,12 +235,11 @@ void SubpixelFiller::Render(int val, int len)
while(t < e) while(t < e)
AlphaBlendCover8(*t++, ss ? Mul8(*s++, alpha) : color, val); AlphaBlendCover8(*t++, ss ? Mul8(*s++, alpha) : color, val);
v = begin = sbuffer + 3; v = begin = sbuffer + 3;
int h = val / 9;
v[0] = h + h + h; v[0] = h + h + h;
v[1] = h; v[1] = h;
v[2] = 0; v[2] = 0;
} }
RenderN(val, len); RenderN(val, h, len);
} }
void SubpixelFiller::Write(int len) void SubpixelFiller::Write(int len)
@ -249,29 +248,22 @@ void SubpixelFiller::Write(int len)
int16 *q = begin; int16 *q = begin;
while(t < e) { while(t < e) {
RGBA c = ss ? Mul8(*s++, alpha) : color; RGBA c = ss ? Mul8(*s++, alpha) : color;
int a, alpha; int a;
if(t->a != 255) if(t->a != 255)
AlphaBlendCover8(*t, c, (q[0] + q[1] + q[2]) / 3); AlphaBlendCover8(*t, c, (q[0] + q[1] + q[2]) / 3);
else { else
if(c.a == 255) { if(c.a == 255) {
alpha = 256 - q[0]; t->r = (c.r * q[0] >> 8) + ((257 - q[0]) * t->r >> 8);
t->r = (c.r * q[0] >> 8) + (alpha * t->r >> 8); t->g = (c.g * q[1] >> 8) + ((257 - q[1]) * t->g >> 8);
alpha = 256 - q[1]; t->b = (c.b * q[2] >> 8) + ((257 - q[2]) * t->b >> 8);
t->g = (c.g * q[1] >> 8) + (alpha * t->g >> 8);
alpha = 256 - q[2];
t->b = (c.b * q[2] >> 8) + (alpha * t->b >> 8);
} }
else { else {
a = c.a * q[0] >> 8; a = c.a * q[0] >> 8;
alpha = 256 - a - (a >> 7); t->r = (c.r * q[0] >> 8) + ((256 - a - (a >> 7)) * t->r >> 8);
t->r = (c.r * q[0] >> 8) + (alpha * t->r >> 8);
a = c.a * q[1] >> 8; a = c.a * q[1] >> 8;
alpha = 256 - a - (a >> 7); t->g = (c.g * q[1] >> 8) + ((256 - a - (a >> 7)) * t->g >> 8);
t->g = (c.g * q[1] >> 8) + (alpha * t->g >> 8);
a = c.a * q[2] >> 8; a = c.a * q[2] >> 8;
alpha = 256 - a - (a >> 7); t->b = (c.b * q[2] >> 8) + ((256 - a - (a >> 7)) * t->b >> 8);
t->b = (c.b * q[2] >> 8) + (alpha * t->b >> 8);
}
} }
t++; t++;
q += 3; q += 3;

View file

@ -35,7 +35,7 @@ struct SubpixelFiller : Rasterizer::Filler {
int y; int y;
void Write(int len); void Write(int len);
void RenderN(int val, int n); void RenderN(int val, int h, int n);
void Render2(int val); void Render2(int val);
void Render1(int val); void Render1(int val);

View file

@ -21,38 +21,37 @@ NAMESPACE_UPP
#ifdef PLATFORM_WIN32 #ifdef PLATFORM_WIN32
inline double fx_to_dbl(const FIXED& p) { double fx_to_dbl(const FIXED& p) {
return double(p.value) + double(p.fract) * (1.0 / 65536.0); return double(p.value) + double(p.fract) * (1.0 / 65536.0);
} }
Pointf fx_to_dbl(const Pointf& pp, const POINTFX& p) {
return Pointf(pp.x + fx_to_dbl(p.x), pp.y - fx_to_dbl(p.y));
}
void RenderCharPath(const char* gbuf, unsigned total_size, Painter& sw, double xx, double yy) void RenderCharPath(const char* gbuf, unsigned total_size, Painter& sw, double xx, double yy)
{ {
PAINTER_TIMING("RenderCharPath"); PAINTER_TIMING("RenderCharPath");
const char* cur_glyph = gbuf; const char* cur_glyph = gbuf;
const char* end_glyph = gbuf + total_size; const char* end_glyph = gbuf + total_size;
Pointf pp(xx, yy);
while(cur_glyph < end_glyph) { while(cur_glyph < end_glyph) {
const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph; const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
const char* end_poly = cur_glyph + th->cb; const char* end_poly = cur_glyph + th->cb;
const char* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER); const char* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
sw.Move(xx + fx_to_dbl(th->pfxStart.x), yy - fx_to_dbl(th->pfxStart.y)); sw.Move(fx_to_dbl(pp, th->pfxStart));
while(cur_poly < end_poly) { while(cur_poly < end_poly) {
const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly; const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
if (pc->wType == TT_PRIM_LINE) if (pc->wType == TT_PRIM_LINE)
for(int i = 0; i < pc->cpfx; i++) for(int i = 0; i < pc->cpfx; i++)
sw.Line(xx + fx_to_dbl(pc->apfx[i].x), yy - fx_to_dbl(pc->apfx[i].y)); sw.Line(fx_to_dbl(pp, pc->apfx[i]));
if (pc->wType == TT_PRIM_QSPLINE) { if (pc->wType == TT_PRIM_QSPLINE)
int u; for(int u = 0; u < pc->cpfx - 1; u++) {
for (u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline Pointf b = fx_to_dbl(pp, pc->apfx[u]);
POINTFX pnt_b = pc->apfx[u]; // B is always the current point Pointf c = fx_to_dbl(pp, pc->apfx[u + 1]);
POINTFX pnt_c = pc->apfx[u+1]; if (u < pc->cpfx - 2)
if (u < pc->cpfx - 2) { // If not on last spline, compute C c = Mid(b, c);
*(int*)&pnt_c.x = (*(int*)&pnt_b.x + *(int*)&pnt_c.x) / 2; sw.Quadratic(b, c);
*(int*)&pnt_c.y = (*(int*)&pnt_b.y + *(int*)&pnt_c.y) / 2;
}
sw.Quadratic(xx + fx_to_dbl(pnt_b.x), yy - fx_to_dbl(pnt_b.y),
xx + fx_to_dbl(pnt_c.x), yy - fx_to_dbl(pnt_c.y));
}
} }
cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx; cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
} }

View file

@ -34,7 +34,8 @@ file
Image.cpp optimize_speed, Image.cpp optimize_speed,
Mask.cpp optimize_speed, Mask.cpp optimize_speed,
Gradient.cpp optimize_speed, Gradient.cpp optimize_speed,
RadialGradient.cpp optimize_speed; RadialGradient.cpp optimize_speed,
srcimp.tpp;
mainconfig mainconfig
"" = "GUI"; "" = "GUI";

View file

@ -2,7 +2,7 @@
#define _Painter_icpp_init_stub #define _Painter_icpp_init_stub
#include "Core/init" #include "Core/init"
#include "CtrlLib/init" #include "CtrlLib/init"
#define BLITZ_INDEX__ F135B9991BD270784ACE22BD4FFB4267E #define BLITZ_INDEX__ F1F279540D3FE6AF9024371A0E93C1FBB
#include "PaintPainting.icpp" #include "PaintPainting.icpp"
#undef BLITZ_INDEX__ #undef BLITZ_INDEX__
#endif #endif

View file

@ -0,0 +1,17 @@
topic "";
[ $$0,0#00000000000000000000000000000000:Default]
[H6;0 $$1,0#05600065144404261032431302351956:begin]
[i448;a25;kKO9;2 $$2,0#37138531426314131252341829483370:codeitem]
[l288;2 $$3,0#27521748481378242620020725143825:desc]
[0 $$4,0#96390100711032703541132217272105:end]
[{_}%EN-US
[s1;%- &]
[s2;:SubpixelFiller`:`:Write`(int`):%- [@(0.0.255) void]_[* Write]([@(0.0.255) int]_[*@3 len])
&]
[s3; This function flushes the content of filtered subpixel buffer.&]
[s0; Important note: due to rounding errors during filtering, sometimes
the subpixel value can be 257. This is remedied by using 257
instead of 256 in the pixel blending command.&]
[s0; &]
[s4; &]
[s0; ]