Fix Fill Behavior on Toonz Raster (#1540)

* fix raster fill

* fix for one pixel width line case

* fix rect fill
This commit is contained in:
shun-iwasawa 2017-11-22 12:38:37 +09:00 committed by masafumi-inoue
parent 2a679ac119
commit f9d3f02167
3 changed files with 81 additions and 10 deletions

View file

@ -27,6 +27,7 @@ public:
bool m_shiftFill;
TPoint m_p;
TPalette *m_palette;
bool m_prevailing;
FillParameters()
: m_styleId(0)
@ -37,7 +38,8 @@ public:
, m_maxFillDepth(0)
, m_p()
, m_shiftFill(false)
, m_palette(0) {}
, m_palette(0)
, m_prevailing(true) {}
FillParameters(const FillParameters &params)
: m_styleId(params.m_styleId)
, m_fillType(params.m_fillType)
@ -47,7 +49,8 @@ public:
, m_maxFillDepth(params.m_maxFillDepth)
, m_p(params.m_p)
, m_shiftFill(params.m_shiftFill)
, m_palette(params.m_palette) {}
, m_palette(params.m_palette)
, m_prevailing(params.m_prevailing) {}
};
//=============================================================================

View file

@ -32,9 +32,14 @@ inline TPoint nearestInkNotDiagonal(const TRasterCM32P &r, const TPoint &p) {
// la riga ridisegnata va da *xa a *xb compresi
// x1 <= *xa <= *xb <= x2
// N.B. se non viene disegnato neanche un pixel *xa>*xb
//
// "prevailing" is set to false on revert-filling the border of
// region in the Rectangular, Freehand and Polyline fill procedures
// in order to make the paint to protlude behind the line.
void fillRow(const TRasterCM32P &r, const TPoint &p, int &xa, int &xb,
int paint, TPalette *palette, TTileSaverCM32 *saver) {
int paint, TPalette *palette, TTileSaverCM32 *saver,
bool prevailing = true) {
int tone, oldtone;
TPixelCM32 *pix, *pix0, *limit, *tmp_limit;
@ -49,7 +54,34 @@ void fillRow(const TRasterCM32P &r, const TPoint &p, int &xa, int &xb,
for (; pix <= limit; pix++) {
if (pix->getPaint() == paint) break;
tone = pix->getTone();
if (tone > oldtone || tone == 0) break;
if (tone == 0) break;
// prevent fill area from protruding behind the colored line
if (tone > oldtone) {
// not-yet-colored line case
if (prevailing && !pix->isPurePaint() && pix->getInk() != pix->getPaint())
break;
while (pix != pix0) {
// iterate back in order to leave the pixel with the lowest tone
// unpainted
pix--;
// make the one-pixel-width semi-transparent line to be painted
if (prevailing && pix->getInk() != pix->getPaint()) break;
if (pix->getTone() > oldtone) {
// check if the current pixel is NOT with the lowest tone among the
// vertical neighbors as well
if (p.y > 0 && p.y < r->getLy() - 1) {
TPixelCM32 *upPix = pix - r->getWrap();
TPixelCM32 *downPix = pix + r->getWrap();
if (upPix->getTone() > pix->getTone() &&
downPix->getTone() > pix->getTone())
continue;
}
break;
}
}
pix++;
break;
}
oldtone = tone;
}
if (tone == 0) {
@ -72,7 +104,34 @@ void fillRow(const TRasterCM32P &r, const TPoint &p, int &xa, int &xb,
for (pix--; pix >= limit; pix--) {
if (pix->getPaint() == paint) break;
tone = pix->getTone();
if (tone > oldtone || tone == 0) break;
if (tone == 0) break;
// prevent fill area from protruding behind the colored line
if (tone > oldtone) {
// not-yet-colored line case
if (prevailing && !pix->isPurePaint() && pix->getInk() != pix->getPaint())
break;
while (pix != pix0) {
// iterate forward in order to leave the pixel with the lowest tone
// unpainted
pix++;
// make the one-pixel-width semi-transparent line to be painted
if (prevailing && pix->getInk() != pix->getPaint()) break;
if (pix->getTone() > oldtone) {
// check if the current pixel is NOT with the lowest tone among the
// vertical neighbors as well
if (p.y > 0 && p.y < r->getLy() - 1) {
TPixelCM32 *upPix = pix - r->getWrap();
TPixelCM32 *downPix = pix + r->getWrap();
if (upPix->getTone() > pix->getTone() &&
downPix->getTone() > pix->getTone())
continue;
}
break;
}
}
pix--;
break;
}
oldtone = tone;
}
if (tone == 0) {
@ -234,7 +293,8 @@ bool fill(const TRasterCM32P &r, const FillParameters &params,
/*- 画面外のクリックの場合はreturn -*/
if (!bbbox.contains(p)) return false;
/*- 既に同じ色が塗られている場合はreturn -*/
if ((r->pixels(p.y) + p.x)->getPaint() == paint) return false;
int paintAtClickedPos = (r->pixels(p.y) + p.x)->getPaint();
if (paintAtClickedPos == paint) return false;
/*- 「透明部分だけを塗る」オプションが有効で、既に色が付いている場合はreturn
* -*/
if (params.m_emptyOnly && (r->pixels(p.y) + p.x)->getPaint() != 0)
@ -252,7 +312,6 @@ bool fill(const TRasterCM32P &r, const FillParameters &params,
default:
assert(false);
}
/*-- 四隅の色を見て、一つでも変わったらsaveBoxを更新する --*/
TPixelCM32 borderIndex[4];
TPixelCM32 *borderPix[4];
@ -271,7 +330,7 @@ bool fill(const TRasterCM32P &r, const FillParameters &params,
std::stack<FillSeed> seeds;
fillRow(r, p, xa, xb, paint, params.m_palette, saver);
fillRow(r, p, xa, xb, paint, params.m_palette, saver, params.m_prevailing);
seeds.push(FillSeed(xa, xb, y, 1));
seeds.push(FillSeed(xa, xb, y, -1));
@ -294,8 +353,13 @@ bool fill(const TRasterCM32P &r, const FillParameters &params,
while (pix <= limit) {
oldtone = threshTone(*oldpix, fillDepth);
tone = threshTone(*pix, fillDepth);
if (pix->getPaint() != paint && tone <= oldtone && tone != 0) {
fillRow(r, TPoint(x, y), xc, xd, paint, params.m_palette, saver);
// the last condition is added in order to prevent fill area from
// protruding behind the colored line
if (pix->getPaint() != paint && tone <= oldtone && tone != 0 &&
(pix->getPaint() != pix->getInk() ||
pix->getPaint() == paintAtClickedPos)) {
fillRow(r, TPoint(x, y), xc, xd, paint, params.m_palette, saver,
params.m_prevailing);
if (xc < xa) seeds.push(FillSeed(xc, xa - 1, y, -dy));
if (xd > xb) seeds.push(FillSeed(xb + 1, xd, y, -dy));
if (oldxd >= xc - 1)

View file

@ -69,6 +69,8 @@ void fillArea(const TRasterCM32P &ras, TRegion *r, int colorId,
void restoreColors(const TRasterCM32P &r,
const std::vector<std::pair<TPoint, int>> &seeds) {
FillParameters params;
// in order to make the paint to protlude behind the line
params.m_prevailing = false;
for (UINT i = 0; i < seeds.size(); i++) {
params.m_p = seeds[i].first;
params.m_styleId = seeds[i].second;
@ -232,6 +234,8 @@ void AreaFiller::rectFill(const TRect &rect, int color, bool onlyUnfilled,
// fillate.
count1 = 0;
FillParameters params;
// in order to make the paint to protlude behind the line
params.m_prevailing = false;
if (r.x0 > 0)
for (y = r.y0; y <= r.y1; y++) {
params.m_p = TPoint(r.x0, y);