|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "trastercm.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/fill.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/ttilesaver.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tpalette.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tpixelutils.h"
|
|
Toshihiro Shimizu |
890ddd |
#include <stack></stack>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Shinya Kitaoka |
120a6e |
namespace { // Utility Function
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
inline TPoint nearestInkNotDiagonal(const TRasterCM32P &r, const TPoint &p) {
|
|
Shinya Kitaoka |
120a6e |
TPixelCM32 *buf = (TPixelCM32 *)r->pixels(p.y) + p.x;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (p.x < r->getLx() - 1 && (!(buf + 1)->isPurePaint()))
|
|
Shinya Kitaoka |
120a6e |
return TPoint(p.x + 1, p.y);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (p.x > 0 && (!(buf - 1)->isPurePaint())) return TPoint(p.x - 1, p.y);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (p.y < r->getLy() - 1 && (!(buf + r->getWrap())->isPurePaint()))
|
|
Shinya Kitaoka |
120a6e |
return TPoint(p.x, p.y + 1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (p.y > 0 && (!(buf - r->getWrap())->isPurePaint()))
|
|
Shinya Kitaoka |
120a6e |
return TPoint(p.x, p.y - 1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
return TPoint(-1, -1);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// dal punto x,y si espande a destra e a sinistra.
|
|
Toshihiro Shimizu |
890ddd |
// la riga ridisegnata va da *xa a *xb compresi
|
|
Toshihiro Shimizu |
890ddd |
// x1 <= *xa <= *xb <= x2
|
|
Toshihiro Shimizu |
890ddd |
// N.B. se non viene disegnato neanche un pixel *xa>*xb
|
|
shun-iwasawa |
f9d3f0 |
//
|
|
shun-iwasawa |
f9d3f0 |
// "prevailing" is set to false on revert-filling the border of
|
|
shun-iwasawa |
f9d3f0 |
// region in the Rectangular, Freehand and Polyline fill procedures
|
|
shun-iwasawa |
f9d3f0 |
// in order to make the paint to protlude behind the line.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void fillRow(const TRasterCM32P &r, const TPoint &p, int &xa, int &xb,
|
|
shun-iwasawa |
f9d3f0 |
int paint, TPalette *palette, TTileSaverCM32 *saver,
|
|
shun-iwasawa |
f9d3f0 |
bool prevailing = true) {
|
|
Shinya Kitaoka |
120a6e |
int tone, oldtone;
|
|
Shinya Kitaoka |
120a6e |
TPixelCM32 *pix, *pix0, *limit, *tmp_limit;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
/* vai a destra */
|
|
Shinya Kitaoka |
120a6e |
TPixelCM32 *line = r->pixels(p.y);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
pix0 = line + p.x;
|
|
Shinya Kitaoka |
120a6e |
pix = pix0;
|
|
Shinya Kitaoka |
120a6e |
limit = line + r->getBounds().x1;
|
|
Shinya Kitaoka |
120a6e |
oldtone = pix->getTone();
|
|
Shinya Kitaoka |
120a6e |
tone = oldtone;
|
|
Shinya Kitaoka |
120a6e |
for (; pix <= limit; pix++) {
|
|
Shinya Kitaoka |
120a6e |
if (pix->getPaint() == paint) break;
|
|
Shinya Kitaoka |
120a6e |
tone = pix->getTone();
|
|
shun-iwasawa |
f9d3f0 |
if (tone == 0) break;
|
|
shun-iwasawa |
f9d3f0 |
// prevent fill area from protruding behind the colored line
|
|
shun-iwasawa |
f9d3f0 |
if (tone > oldtone) {
|
|
shun-iwasawa |
f9d3f0 |
// not-yet-colored line case
|
|
shun-iwasawa |
f9d3f0 |
if (prevailing && !pix->isPurePaint() && pix->getInk() != pix->getPaint())
|
|
shun-iwasawa |
f9d3f0 |
break;
|
|
shun-iwasawa |
f9d3f0 |
while (pix != pix0) {
|
|
shun-iwasawa |
f9d3f0 |
// iterate back in order to leave the pixel with the lowest tone
|
|
shun-iwasawa |
f9d3f0 |
// unpainted
|
|
shun-iwasawa |
f9d3f0 |
pix--;
|
|
shun-iwasawa |
f9d3f0 |
// make the one-pixel-width semi-transparent line to be painted
|
|
shun-iwasawa |
f9d3f0 |
if (prevailing && pix->getInk() != pix->getPaint()) break;
|
|
shun-iwasawa |
f9d3f0 |
if (pix->getTone() > oldtone) {
|
|
shun-iwasawa |
f9d3f0 |
// check if the current pixel is NOT with the lowest tone among the
|
|
shun-iwasawa |
f9d3f0 |
// vertical neighbors as well
|
|
shun-iwasawa |
f9d3f0 |
if (p.y > 0 && p.y < r->getLy() - 1) {
|
|
shun-iwasawa |
f9d3f0 |
TPixelCM32 *upPix = pix - r->getWrap();
|
|
shun-iwasawa |
f9d3f0 |
TPixelCM32 *downPix = pix + r->getWrap();
|
|
shun-iwasawa |
f9d3f0 |
if (upPix->getTone() > pix->getTone() &&
|
|
shun-iwasawa |
f9d3f0 |
downPix->getTone() > pix->getTone())
|
|
shun-iwasawa |
f9d3f0 |
continue;
|
|
shun-iwasawa |
f9d3f0 |
}
|
|
shun-iwasawa |
f9d3f0 |
break;
|
|
shun-iwasawa |
f9d3f0 |
}
|
|
shun-iwasawa |
f9d3f0 |
}
|
|
shun-iwasawa |
f9d3f0 |
pix++;
|
|
shun-iwasawa |
f9d3f0 |
break;
|
|
shun-iwasawa |
f9d3f0 |
}
|
|
Shinya Kitaoka |
120a6e |
oldtone = tone;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
if (tone == 0) {
|
|
Shinya Kitaoka |
38fd86 |
tmp_limit = pix + 10; // edge stop fill == 10 per default
|
|
Shinya Kitaoka |
120a6e |
if (limit > tmp_limit) limit = tmp_limit;
|
|
Shinya Kitaoka |
120a6e |
for (; pix <= limit; pix++) {
|
|
Shinya Kitaoka |
120a6e |
if (pix->getPaint() == paint) break;
|
|
Shinya Kitaoka |
120a6e |
if (pix->getTone() != 0) break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
xb = p.x + pix - pix0 - 1;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
/* vai a sinistra */
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
pix = pix0;
|
|
Shinya Kitaoka |
120a6e |
limit = line + r->getBounds().x0;
|
|
Shinya Kitaoka |
120a6e |
oldtone = pix->getTone();
|
|
Shinya Kitaoka |
120a6e |
tone = oldtone;
|
|
Shinya Kitaoka |
120a6e |
for (pix--; pix >= limit; pix--) {
|
|
Shinya Kitaoka |
120a6e |
if (pix->getPaint() == paint) break;
|
|
Shinya Kitaoka |
120a6e |
tone = pix->getTone();
|
|
shun-iwasawa |
f9d3f0 |
if (tone == 0) break;
|
|
shun-iwasawa |
f9d3f0 |
// prevent fill area from protruding behind the colored line
|
|
shun-iwasawa |
f9d3f0 |
if (tone > oldtone) {
|
|
shun-iwasawa |
f9d3f0 |
// not-yet-colored line case
|
|
shun-iwasawa |
f9d3f0 |
if (prevailing && !pix->isPurePaint() && pix->getInk() != pix->getPaint())
|
|
shun-iwasawa |
f9d3f0 |
break;
|
|
shun-iwasawa |
f9d3f0 |
while (pix != pix0) {
|
|
shun-iwasawa |
f9d3f0 |
// iterate forward in order to leave the pixel with the lowest tone
|
|
shun-iwasawa |
f9d3f0 |
// unpainted
|
|
shun-iwasawa |
f9d3f0 |
pix++;
|
|
shun-iwasawa |
f9d3f0 |
// make the one-pixel-width semi-transparent line to be painted
|
|
shun-iwasawa |
f9d3f0 |
if (prevailing && pix->getInk() != pix->getPaint()) break;
|
|
shun-iwasawa |
f9d3f0 |
if (pix->getTone() > oldtone) {
|
|
shun-iwasawa |
f9d3f0 |
// check if the current pixel is NOT with the lowest tone among the
|
|
shun-iwasawa |
f9d3f0 |
// vertical neighbors as well
|
|
shun-iwasawa |
f9d3f0 |
if (p.y > 0 && p.y < r->getLy() - 1) {
|
|
shun-iwasawa |
f9d3f0 |
TPixelCM32 *upPix = pix - r->getWrap();
|
|
shun-iwasawa |
f9d3f0 |
TPixelCM32 *downPix = pix + r->getWrap();
|
|
shun-iwasawa |
f9d3f0 |
if (upPix->getTone() > pix->getTone() &&
|
|
shun-iwasawa |
f9d3f0 |
downPix->getTone() > pix->getTone())
|
|
shun-iwasawa |
f9d3f0 |
continue;
|
|
shun-iwasawa |
f9d3f0 |
}
|
|
shun-iwasawa |
f9d3f0 |
break;
|
|
shun-iwasawa |
f9d3f0 |
}
|
|
shun-iwasawa |
f9d3f0 |
}
|
|
shun-iwasawa |
f9d3f0 |
pix--;
|
|
shun-iwasawa |
f9d3f0 |
break;
|
|
shun-iwasawa |
f9d3f0 |
}
|
|
Shinya Kitaoka |
120a6e |
oldtone = tone;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
if (tone == 0) {
|
|
shun-iwasawa |
443318 |
tmp_limit = pix - 10;
|
|
Shinya Kitaoka |
120a6e |
if (limit < tmp_limit) limit = tmp_limit;
|
|
Shinya Kitaoka |
120a6e |
for (; pix >= limit; pix--) {
|
|
Shinya Kitaoka |
120a6e |
if (pix->getPaint() == paint) break;
|
|
Shinya Kitaoka |
120a6e |
if (pix->getTone() != 0) break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
xa = p.x + pix - pix0 + 1;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (saver) saver->save(TRect(xa, p.y, xb, p.y));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (xb >= xa) {
|
|
Shinya Kitaoka |
120a6e |
pix = line + xa;
|
|
Shinya Kitaoka |
120a6e |
int n;
|
|
Shinya Kitaoka |
120a6e |
for (n = 0; n < xb - xa + 1; n++, pix++) {
|
|
Shinya Kitaoka |
120a6e |
if (palette && pix->isPurePaint()) {
|
|
Shinya Kitaoka |
120a6e |
TPoint pInk = nearestInkNotDiagonal(r, TPoint(xa + n, p.y));
|
|
Shinya Kitaoka |
120a6e |
if (pInk != TPoint(-1, -1)) {
|
|
Shinya Kitaoka |
120a6e |
TPixelCM32 *pixInk =
|
|
Shinya Kitaoka |
120a6e |
(TPixelCM32 *)r->getRawData() + (pInk.y * r->getWrap() + pInk.x);
|
|
Shinya Kitaoka |
120a6e |
if (pixInk->getInk() != paint &&
|
|
Shinya Kitaoka |
120a6e |
palette->getStyle(pixInk->getInk())->getFlags() != 0)
|
|
Shinya Kitaoka |
120a6e |
inkFill(r, pInk, paint, 0, saver);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
pix->setPaint(paint);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void findSegment(const TRaster32P &r, const TPoint &p, int &xa, int &xb,
|
|
shun-iwasawa |
14c787 |
const TPixel32 &color, const int fillDepth = 254) {
|
|
Shinya Kitaoka |
120a6e |
int matte, oldmatte;
|
|
Shinya Kitaoka |
120a6e |
TPixel32 *pix, *pix0, *limit, *tmp_limit;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
/* vai a destra */
|
|
Shinya Kitaoka |
120a6e |
TPixel32 *line = r->pixels(p.y);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
pix0 = line + p.x;
|
|
Shinya Kitaoka |
120a6e |
pix = pix0;
|
|
Shinya Kitaoka |
120a6e |
limit = line + r->getBounds().x1;
|
|
Shinya Kitaoka |
120a6e |
oldmatte = pix->m;
|
|
Shinya Kitaoka |
120a6e |
matte = oldmatte;
|
|
Shinya Kitaoka |
120a6e |
for (; pix <= limit; pix++) {
|
|
Shinya Kitaoka |
120a6e |
if (*pix == color) break;
|
|
Shinya Kitaoka |
120a6e |
matte = pix->m;
|
|
shun-iwasawa |
14c787 |
if (matte < oldmatte || matte > fillDepth) break;
|
|
Shinya Kitaoka |
120a6e |
oldmatte = matte;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
if (matte == 0) {
|
|
Shinya Kitaoka |
38fd86 |
tmp_limit = pix + 10; // edge stop fill == 10 per default
|
|
Shinya Kitaoka |
120a6e |
if (limit > tmp_limit) limit = tmp_limit;
|
|
Shinya Kitaoka |
120a6e |
for (; pix <= limit; pix++) {
|
|
Shinya Kitaoka |
120a6e |
if (*pix == color) break;
|
|
Shinya Kitaoka |
120a6e |
if (pix->m != 255) break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
xb = p.x + pix - pix0 - 1;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
/* vai a sinistra */
|
|
Shinya Kitaoka |
120a6e |
pix = pix0;
|
|
Shinya Kitaoka |
120a6e |
limit = line + r->getBounds().x0;
|
|
Shinya Kitaoka |
120a6e |
oldmatte = pix->m;
|
|
Shinya Kitaoka |
120a6e |
matte = oldmatte;
|
|
Shinya Kitaoka |
120a6e |
for (; pix >= limit; pix--) {
|
|
Shinya Kitaoka |
120a6e |
if (*pix == color) break;
|
|
Shinya Kitaoka |
120a6e |
matte = pix->m;
|
|
shun-iwasawa |
14c787 |
if (matte < oldmatte || matte > fillDepth) break;
|
|
Shinya Kitaoka |
120a6e |
oldmatte = matte;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
if (matte == 0) {
|
|
shun-iwasawa |
443318 |
tmp_limit = pix - 10;
|
|
Shinya Kitaoka |
120a6e |
if (limit < tmp_limit) limit = tmp_limit;
|
|
Shinya Kitaoka |
120a6e |
for (; pix >= limit; pix--) {
|
|
Shinya Kitaoka |
120a6e |
if (*pix == color) break;
|
|
Shinya Kitaoka |
120a6e |
if (pix->m != 255) break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
xa = p.x + pix - pix0 + 1;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
shun-iwasawa |
14c787 |
// Used when the clicked pixel is solid or semi-transparent.
|
|
shun-iwasawa |
14c787 |
// Check if the fill is stemmed at the target pixel.
|
|
shun-iwasawa |
14c787 |
// Note that RGB values are used for checking the difference, not Alpha value.
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
bool doesStemFill(const TPixel32 &clickColor, const TPixel32 *targetPix,
|
|
shun-iwasawa |
14c787 |
const int fillDepth2) {
|
|
shun-iwasawa |
14c787 |
// stop if the target pixel is transparent
|
|
shun-iwasawa |
14c787 |
if (targetPix->m == 0) return true;
|
|
shun-iwasawa |
14c787 |
// check difference of RGB values is larger than fillDepth
|
|
shun-iwasawa |
14c787 |
int dr = (int)clickColor.r - (int)targetPix->r;
|
|
shun-iwasawa |
14c787 |
int dg = (int)clickColor.g - (int)targetPix->g;
|
|
shun-iwasawa |
14c787 |
int db = (int)clickColor.b - (int)targetPix->b;
|
|
shun-iwasawa |
14c787 |
return (dr * dr + dg * dg + db * db) >
|
|
shun-iwasawa |
14c787 |
fillDepth2; // condition for "stem" the fill
|
|
shun-iwasawa |
14c787 |
}
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
//-----------------------------------------------------------------------------
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
void fullColorFindSegment(const TRaster32P &r, const TPoint &p, int &xa,
|
|
shun-iwasawa |
14c787 |
int &xb, const TPixel32 &color,
|
|
shun-iwasawa |
14c787 |
const TPixel32 &clickedPosColor,
|
|
shun-iwasawa |
14c787 |
const int fillDepth) {
|
|
shun-iwasawa |
14c787 |
if (clickedPosColor.m == 0) {
|
|
shun-iwasawa |
14c787 |
findSegment(r, p, xa, xb, color, fillDepth);
|
|
shun-iwasawa |
14c787 |
return;
|
|
shun-iwasawa |
14c787 |
}
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
TPixel32 *pix, *pix0, *limit;
|
|
shun-iwasawa |
14c787 |
// check to the right
|
|
shun-iwasawa |
14c787 |
TPixel32 *line = r->pixels(p.y);
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
pix0 = line + p.x; // seed pixel
|
|
shun-iwasawa |
14c787 |
pix = pix0;
|
|
shun-iwasawa |
14c787 |
limit = line + r->getBounds().x1; // right end
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
TPixel32 oldPix = *pix;
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
int fillDepth2 = fillDepth * fillDepth;
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
for (; pix <= limit; pix++) {
|
|
shun-iwasawa |
14c787 |
// break if the target pixel is with the same as filling color
|
|
shun-iwasawa |
14c787 |
if (*pix == color) break;
|
|
shun-iwasawa |
14c787 |
// continue if the target pixel is the same as the previous one
|
|
shun-iwasawa |
14c787 |
if (*pix == oldPix) continue;
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
if (doesStemFill(clickedPosColor, pix, fillDepth2)) break;
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
// store pixel color in case if the next pixel is with the same color
|
|
shun-iwasawa |
14c787 |
oldPix = *pix;
|
|
shun-iwasawa |
14c787 |
}
|
|
shun-iwasawa |
14c787 |
xb = p.x + pix - pix0 - 1;
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
// check to the left
|
|
shun-iwasawa |
14c787 |
pix = pix0; // seed pixel
|
|
shun-iwasawa |
14c787 |
limit = line + r->getBounds().x0; // left end
|
|
shun-iwasawa |
14c787 |
oldPix = *pix;
|
|
shun-iwasawa |
14c787 |
for (; pix >= limit; pix--) {
|
|
shun-iwasawa |
14c787 |
// break if the target pixel is with the same as filling color
|
|
shun-iwasawa |
14c787 |
if (*pix == color) break;
|
|
shun-iwasawa |
14c787 |
// continue if the target pixel is the same as the previous one
|
|
shun-iwasawa |
14c787 |
if (*pix == oldPix) continue;
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
if (doesStemFill(clickedPosColor, pix, fillDepth2)) break;
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
// store pixel color in case if the next pixel is with the same color
|
|
shun-iwasawa |
14c787 |
oldPix = *pix;
|
|
shun-iwasawa |
14c787 |
}
|
|
shun-iwasawa |
14c787 |
xa = p.x + pix - pix0 + 1;
|
|
shun-iwasawa |
14c787 |
}
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
class FillSeed {
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
int m_xa, m_xb;
|
|
Shinya Kitaoka |
120a6e |
int m_y, m_dy;
|
|
Shinya Kitaoka |
120a6e |
FillSeed(int xa, int xb, int y, int dy)
|
|
Shinya Kitaoka |
120a6e |
: m_xa(xa), m_xb(xb), m_y(y), m_dy(dy) {}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
inline int threshTone(const TPixelCM32 &pix, int fillDepth) {
|
|
Shinya Kitaoka |
120a6e |
if (fillDepth == TPixelCM32::getMaxTone())
|
|
Shinya Kitaoka |
120a6e |
return pix.getTone();
|
|
Shinya Kitaoka |
120a6e |
else
|
|
Shinya Kitaoka |
120a6e |
return ((pix.getTone()) > fillDepth) ? TPixelCM32::getMaxTone()
|
|
Shinya Kitaoka |
120a6e |
: pix.getTone();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
inline int threshMatte(int matte, int fillDepth) {
|
|
Shinya Kitaoka |
120a6e |
if (fillDepth == 255)
|
|
Shinya Kitaoka |
120a6e |
return matte;
|
|
Shinya Kitaoka |
120a6e |
else
|
|
Shinya Kitaoka |
120a6e |
return (matte < fillDepth) ? 255 : matte;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
bool isPixelInSegment(const std::vector<std::pair<int, int="">> &segments, int x) {</std::pair<int,>
|
|
Shinya Kitaoka |
120a6e |
for (int i = 0; i < (int)segments.size(); i++) {
|
|
Shinya Kitaoka |
120a6e |
std::pair<int, int=""> segment = segments[i];</int,>
|
|
Shinya Kitaoka |
120a6e |
if (segment.first <= x && x <= segment.second) return true;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void insertSegment(std::vector<std::pair<int, int="">> &segments,</std::pair<int,>
|
|
Shinya Kitaoka |
120a6e |
const std::pair<int, int=""> segment) {</int,>
|
|
Shinya Kitaoka |
120a6e |
for (int i = segments.size() - 1; i >= 0; i--) {
|
|
Shinya Kitaoka |
120a6e |
std::pair<int, int=""> app = segments[i];</int,>
|
|
Shinya Kitaoka |
120a6e |
if (segment.first <= app.first && app.second <= segment.second)
|
|
Shinya Kitaoka |
120a6e |
segments.erase(segments.begin() + i);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
segments.push_back(segment);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
bool floodCheck(const TPixel32 &clickColor, const TPixel32 *targetPix,
|
|
shun-iwasawa |
14c787 |
const TPixel32 *oldPix, const int fillDepth) {
|
|
shun-iwasawa |
14c787 |
auto fullColorThreshMatte = [](int matte, int fillDepth) -> int {
|
|
shun-iwasawa |
14c787 |
return (matte <= fillDepth) ? matte : 255;
|
|
shun-iwasawa |
14c787 |
};
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
if (clickColor.m == 0) {
|
|
shun-iwasawa |
14c787 |
int oldMatte = fullColorThreshMatte(oldPix->m, fillDepth);
|
|
shun-iwasawa |
14c787 |
int matte = fullColorThreshMatte(targetPix->m, fillDepth);
|
|
shun-iwasawa |
14c787 |
return matte >= oldMatte && matte != 255;
|
|
shun-iwasawa |
14c787 |
}
|
|
shun-iwasawa |
14c787 |
int fillDepth2 = fillDepth * fillDepth;
|
|
shun-iwasawa |
14c787 |
return !doesStemFill(clickColor, targetPix, fillDepth2);
|
|
shun-iwasawa |
14c787 |
}
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
//-----------------------------------------------------------------------------
|
|
Shinya Kitaoka |
120a6e |
} // namespace
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
shun-iwasawa |
443318 |
/*-- The return value is whether the saveBox has been updated or not. --*/
|
|
Shinya Kitaoka |
120a6e |
bool fill(const TRasterCM32P &r, const FillParameters ¶ms,
|
|
Shinya Kitaoka |
120a6e |
TTileSaverCM32 *saver) {
|
|
Shinya Kitaoka |
120a6e |
TPixelCM32 *pix, *limit, *pix0, *oldpix;
|
|
Shinya Kitaoka |
120a6e |
int oldy, xa, xb, xc, xd, dy;
|
|
Shinya Kitaoka |
120a6e |
int oldxc, oldxd;
|
|
Shinya Kitaoka |
120a6e |
int tone, oldtone;
|
|
Shinya Kitaoka |
120a6e |
TPoint p = params.m_p;
|
|
Shinya Kitaoka |
120a6e |
int x = p.x, y = p.y;
|
|
Shinya Kitaoka |
120a6e |
int paint = params.m_styleId;
|
|
Shinya Kitaoka |
120a6e |
int fillDepth =
|
|
Shinya Kitaoka |
120a6e |
params.m_shiftFill ? params.m_maxFillDepth : params.m_minFillDepth;
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
443318 |
/*-- getBounds returns the entire image --*/
|
|
Shinya Kitaoka |
120a6e |
TRect bbbox = r->getBounds();
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
443318 |
/*- Return if clicked outside the screen -*/
|
|
Shinya Kitaoka |
120a6e |
if (!bbbox.contains(p)) return false;
|
|
shun-iwasawa |
443318 |
/*- If the same color has already been painted, return -*/
|
|
shun-iwasawa |
f9d3f0 |
int paintAtClickedPos = (r->pixels(p.y) + p.x)->getPaint();
|
|
shun-iwasawa |
f9d3f0 |
if (paintAtClickedPos == paint) return false;
|
|
shun-iwasawa |
443318 |
/*- If the "paint only transparent areas" option is enabled and the area is
|
|
shun-iwasawa |
443318 |
* already colored, return
|
|
Shinya Kitaoka |
120a6e |
* -*/
|
|
Shinya Kitaoka |
120a6e |
if (params.m_emptyOnly && (r->pixels(p.y) + p.x)->getPaint() != 0)
|
|
Shinya Kitaoka |
120a6e |
return false;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
assert(fillDepth >= 0 && fillDepth < 16);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
switch (TPixelCM32::getMaxTone()) {
|
|
Shinya Kitaoka |
120a6e |
case 15:
|
|
Shinya Kitaoka |
120a6e |
fillDepth = (15 - fillDepth);
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
case 255:
|
|
Shinya Kitaoka |
120a6e |
fillDepth = ((15 - fillDepth) << 4) | (15 - fillDepth);
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
default:
|
|
Shinya Kitaoka |
120a6e |
assert(false);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
shun-iwasawa |
443318 |
/*--Look at the colors in the four corners and update the saveBox if any of
|
|
shun-iwasawa |
443318 |
* the colors change. --*/
|
|
Shinya Kitaoka |
120a6e |
TPixelCM32 borderIndex[4];
|
|
Shinya Kitaoka |
120a6e |
TPixelCM32 *borderPix[4];
|
|
Shinya Kitaoka |
120a6e |
pix = r->pixels(0);
|
|
Shinya Kitaoka |
120a6e |
borderPix[0] = pix;
|
|
Shinya Kitaoka |
120a6e |
borderIndex[0] = *pix;
|
|
Shinya Kitaoka |
120a6e |
pix += r->getLx() - 1;
|
|
Shinya Kitaoka |
120a6e |
borderPix[1] = pix;
|
|
Shinya Kitaoka |
120a6e |
borderIndex[1] = *pix;
|
|
Shinya Kitaoka |
120a6e |
pix = r->pixels(r->getLy() - 1);
|
|
Shinya Kitaoka |
120a6e |
borderPix[2] = pix;
|
|
Shinya Kitaoka |
120a6e |
borderIndex[2] = *pix;
|
|
Shinya Kitaoka |
120a6e |
pix += r->getLx() - 1;
|
|
Shinya Kitaoka |
120a6e |
borderPix[3] = pix;
|
|
Shinya Kitaoka |
120a6e |
borderIndex[3] = *pix;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
std::stack<fillseed> seeds;</fillseed>
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
f9d3f0 |
fillRow(r, p, xa, xb, paint, params.m_palette, saver, params.m_prevailing);
|
|
Shinya Kitaoka |
120a6e |
seeds.push(FillSeed(xa, xb, y, 1));
|
|
Shinya Kitaoka |
120a6e |
seeds.push(FillSeed(xa, xb, y, -1));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
while (!seeds.empty()) {
|
|
Shinya Kitaoka |
120a6e |
FillSeed fs = seeds.top();
|
|
Shinya Kitaoka |
120a6e |
seeds.pop();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
xa = fs.m_xa;
|
|
Shinya Kitaoka |
120a6e |
xb = fs.m_xb;
|
|
Shinya Kitaoka |
120a6e |
oldy = fs.m_y;
|
|
Shinya Kitaoka |
120a6e |
dy = fs.m_dy;
|
|
Shinya Kitaoka |
120a6e |
y = oldy + dy;
|
|
Shinya Kitaoka |
120a6e |
if (y > bbbox.y1 || y < bbbox.y0) continue;
|
|
Shinya Kitaoka |
120a6e |
pix = pix0 = r->pixels(y) + xa;
|
|
Shinya Kitaoka |
120a6e |
limit = r->pixels(y) + xb;
|
|
Shinya Kitaoka |
120a6e |
oldpix = r->pixels(oldy) + xa;
|
|
Shinya Kitaoka |
120a6e |
x = xa;
|
|
Shinya Kitaoka |
120a6e |
oldxd = (std::numeric_limits<int>::min)();</int>
|
|
Shinya Kitaoka |
120a6e |
oldxc = (std::numeric_limits<int>::max)();</int>
|
|
Shinya Kitaoka |
120a6e |
while (pix <= limit) {
|
|
Shinya Kitaoka |
120a6e |
oldtone = threshTone(*oldpix, fillDepth);
|
|
Shinya Kitaoka |
120a6e |
tone = threshTone(*pix, fillDepth);
|
|
shun-iwasawa |
f9d3f0 |
// the last condition is added in order to prevent fill area from
|
|
shun-iwasawa |
f9d3f0 |
// protruding behind the colored line
|
|
shun-iwasawa |
f9d3f0 |
if (pix->getPaint() != paint && tone <= oldtone && tone != 0 &&
|
|
shun-iwasawa |
f9d3f0 |
(pix->getPaint() != pix->getInk() ||
|
|
shun-iwasawa |
f9d3f0 |
pix->getPaint() == paintAtClickedPos)) {
|
|
shun-iwasawa |
f9d3f0 |
fillRow(r, TPoint(x, y), xc, xd, paint, params.m_palette, saver,
|
|
shun-iwasawa |
f9d3f0 |
params.m_prevailing);
|
|
Shinya Kitaoka |
120a6e |
if (xc < xa) seeds.push(FillSeed(xc, xa - 1, y, -dy));
|
|
Shinya Kitaoka |
120a6e |
if (xd > xb) seeds.push(FillSeed(xb + 1, xd, y, -dy));
|
|
Shinya Kitaoka |
120a6e |
if (oldxd >= xc - 1)
|
|
Shinya Kitaoka |
120a6e |
oldxd = xd;
|
|
Shinya Kitaoka |
120a6e |
else {
|
|
Shinya Kitaoka |
120a6e |
if (oldxd >= 0) seeds.push(FillSeed(oldxc, oldxd, y, dy));
|
|
Shinya Kitaoka |
120a6e |
oldxc = xc;
|
|
Shinya Kitaoka |
120a6e |
oldxd = xd;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
pix += xd - x + 1;
|
|
Shinya Kitaoka |
120a6e |
oldpix += xd - x + 1;
|
|
Shinya Kitaoka |
120a6e |
x += xd - x + 1;
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
pix++;
|
|
Shinya Kitaoka |
120a6e |
oldpix++, x++;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
if (oldxd > 0) seeds.push(FillSeed(oldxc, oldxd, y, dy));
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
bool saveBoxChanged = false;
|
|
Shinya Kitaoka |
120a6e |
for (int i = 0; i < 4; i++) {
|
|
Shinya Kitaoka |
120a6e |
if (!((*borderPix[i]) == borderIndex[i])) {
|
|
Shinya Kitaoka |
120a6e |
saveBoxChanged = true;
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
return saveBoxChanged;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void fill(const TRaster32P &ras, const TRaster32P &ref,
|
|
Shinya Kitaoka |
120a6e |
const FillParameters ¶ms, TTileSaverFullColor *saver) {
|
|
Shinya Kitaoka |
120a6e |
TPixel32 *pix, *limit, *pix0, *oldpix;
|
|
Shinya Kitaoka |
120a6e |
int oldy, xa, xb, xc, xd, dy;
|
|
Shinya Kitaoka |
120a6e |
int oldxc, oldxd;
|
|
Shinya Kitaoka |
120a6e |
int matte, oldMatte;
|
|
Shinya Kitaoka |
120a6e |
int x = params.m_p.x, y = params.m_p.y;
|
|
Shinya Kitaoka |
120a6e |
TRaster32P workRas = ref ? ref : ras;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TRect bbbox = workRas->getBounds();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (!bbbox.contains(params.m_p)) return;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TPaletteP plt = params.m_palette;
|
|
Shinya Kitaoka |
120a6e |
TPixel32 color = plt->getStyle(params.m_styleId)->getMainColor();
|
|
Shinya Kitaoka |
120a6e |
int fillDepth =
|
|
Shinya Kitaoka |
120a6e |
params.m_shiftFill ? params.m_maxFillDepth : params.m_minFillDepth;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
assert(fillDepth >= 0 && fillDepth < 16);
|
|
Shinya Kitaoka |
120a6e |
fillDepth = ((15 - fillDepth) << 4) | (15 - fillDepth);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// looking for any pure transparent pixel along the border; if after filling
|
|
Shinya Kitaoka |
120a6e |
// that pixel will be changed,
|
|
Shinya Kitaoka |
120a6e |
// it means that I filled the bg and the savebox needs to be recomputed!
|
|
Shinya Kitaoka |
120a6e |
TPixel32 borderIndex;
|
|
Shinya Kitaoka |
120a6e |
TPixel32 *borderPix = 0;
|
|
Shinya Kitaoka |
120a6e |
pix = workRas->pixels(0);
|
|
Shinya Kitaoka |
120a6e |
int i;
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < workRas->getLx(); i++, pix++) // border down
|
|
Shinya Kitaoka |
120a6e |
if (pix->m == 0) {
|
|
Shinya Kitaoka |
120a6e |
borderIndex = *pix;
|
|
Shinya Kitaoka |
120a6e |
borderPix = pix;
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
if (borderPix == 0) // not found in border down...try border up (avoid left
|
|
Shinya Kitaoka |
120a6e |
// and right borders...so unlikely)
|
|
Shinya Kitaoka |
120a6e |
{
|
|
Shinya Kitaoka |
120a6e |
pix = workRas->pixels(workRas->getLy() - 1);
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < workRas->getLx(); i++, pix++) // border up
|
|
Shinya Kitaoka |
120a6e |
if (pix->m == 0) {
|
|
Shinya Kitaoka |
120a6e |
borderIndex = *pix;
|
|
Shinya Kitaoka |
120a6e |
borderPix = pix;
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
std::stack<fillseed> seeds;</fillseed>
|
|
Shinya Kitaoka |
120a6e |
std::map<int, int="" std::vector<std::pair<int,="">>> segments;</int,>
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// fillRow(r, params.m_p, xa, xb, color ,saver);
|
|
Shinya Kitaoka |
120a6e |
findSegment(workRas, params.m_p, xa, xb, color);
|
|
Shinya Kitaoka |
120a6e |
segments[y].push_back(std::pair<int, int="">(xa, xb));</int,>
|
|
Shinya Kitaoka |
120a6e |
seeds.push(FillSeed(xa, xb, y, 1));
|
|
Shinya Kitaoka |
120a6e |
seeds.push(FillSeed(xa, xb, y, -1));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
while (!seeds.empty()) {
|
|
Shinya Kitaoka |
120a6e |
FillSeed fs = seeds.top();
|
|
Shinya Kitaoka |
120a6e |
seeds.pop();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
xa = fs.m_xa;
|
|
Shinya Kitaoka |
120a6e |
xb = fs.m_xb;
|
|
Shinya Kitaoka |
120a6e |
oldy = fs.m_y;
|
|
Shinya Kitaoka |
120a6e |
dy = fs.m_dy;
|
|
Shinya Kitaoka |
120a6e |
y = oldy + dy;
|
|
Shinya Kitaoka |
120a6e |
if (y > bbbox.y1 || y < bbbox.y0) continue;
|
|
Shinya Kitaoka |
120a6e |
pix = pix0 = workRas->pixels(y) + xa;
|
|
Shinya Kitaoka |
120a6e |
limit = workRas->pixels(y) + xb;
|
|
Shinya Kitaoka |
120a6e |
oldpix = workRas->pixels(oldy) + xa;
|
|
Shinya Kitaoka |
120a6e |
x = xa;
|
|
Shinya Kitaoka |
120a6e |
oldxd = (std::numeric_limits<int>::min)();</int>
|
|
Shinya Kitaoka |
120a6e |
oldxc = (std::numeric_limits<int>::max)();</int>
|
|
Shinya Kitaoka |
120a6e |
while (pix <= limit) {
|
|
Shinya Kitaoka |
120a6e |
oldMatte = threshMatte(oldpix->m, fillDepth);
|
|
Shinya Kitaoka |
120a6e |
matte = threshMatte(pix->m, fillDepth);
|
|
Shinya Kitaoka |
120a6e |
bool test = false;
|
|
Shinya Kitaoka |
120a6e |
if (segments.find(y) != segments.end())
|
|
Shinya Kitaoka |
120a6e |
test = isPixelInSegment(segments[y], x);
|
|
Shinya Kitaoka |
120a6e |
if (*pix != color && !test && matte >= oldMatte && matte != 255) {
|
|
Shinya Kitaoka |
120a6e |
findSegment(workRas, TPoint(x, y), xc, xd, color);
|
|
Shinya Kitaoka |
120a6e |
// segments[y].push_back(std::pair<int,int>(xc, xd));</int,int>
|
|
Shinya Kitaoka |
120a6e |
insertSegment(segments[y], std::pair<int, int="">(xc, xd));</int,>
|
|
Shinya Kitaoka |
120a6e |
if (xc < xa) seeds.push(FillSeed(xc, xa - 1, y, -dy));
|
|
Shinya Kitaoka |
120a6e |
if (xd > xb) seeds.push(FillSeed(xb + 1, xd, y, -dy));
|
|
Shinya Kitaoka |
120a6e |
if (oldxd >= xc - 1)
|
|
Shinya Kitaoka |
120a6e |
oldxd = xd;
|
|
Shinya Kitaoka |
120a6e |
else {
|
|
Shinya Kitaoka |
120a6e |
if (oldxd >= 0) seeds.push(FillSeed(oldxc, oldxd, y, dy));
|
|
Shinya Kitaoka |
120a6e |
oldxc = xc;
|
|
Shinya Kitaoka |
120a6e |
oldxd = xd;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
pix += xd - x + 1;
|
|
Shinya Kitaoka |
120a6e |
oldpix += xd - x + 1;
|
|
Shinya Kitaoka |
120a6e |
x += xd - x + 1;
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
pix++;
|
|
Shinya Kitaoka |
120a6e |
oldpix++, x++;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
if (oldxd > 0) seeds.push(FillSeed(oldxc, oldxd, y, dy));
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
std::map<int, int="" std::vector<std::pair<int,="">>>::iterator it;</int,>
|
|
Shinya Kitaoka |
120a6e |
for (it = segments.begin(); it != segments.end(); it++) {
|
|
Shinya Kitaoka |
120a6e |
TPixel32 *line = ras->pixels(it->first);
|
|
Shinya Kitaoka |
120a6e |
TPixel32 *refLine = 0;
|
|
Shinya Kitaoka |
120a6e |
TPixel32 *refPix;
|
|
Shinya Kitaoka |
120a6e |
if (ref) refLine = ref->pixels(it->first);
|
|
Shinya Kitaoka |
120a6e |
std::vector<std::pair<int, int="">> segmentVector = it->second;</std::pair<int,>
|
|
Shinya Kitaoka |
120a6e |
for (int i = 0; i < (int)segmentVector.size(); i++) {
|
|
Shinya Kitaoka |
120a6e |
std::pair<int, int=""> segment = segmentVector[i];</int,>
|
|
Shinya Kitaoka |
120a6e |
if (segment.second >= segment.first) {
|
|
shun-iwasawa |
443318 |
pix = line + segment.first;
|
|
Shinya Kitaoka |
120a6e |
if (ref) refPix = refLine + segment.first;
|
|
Shinya Kitaoka |
120a6e |
int n;
|
|
Shinya Kitaoka |
120a6e |
for (n = 0; n < segment.second - segment.first + 1; n++, pix++) {
|
|
Shinya Kitaoka |
120a6e |
if (ref) {
|
|
Shinya Kitaoka |
120a6e |
*pix = *refPix;
|
|
Shinya Kitaoka |
120a6e |
refPix++;
|
|
Shinya Kitaoka |
120a6e |
} else
|
|
Shinya Kitaoka |
120a6e |
*pix = pix->m == 0 ? color : overPix(color, *pix);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
shun-iwasawa |
27b0cf |
static void rectFill(const TRaster32P &ras, const TRect &r,
|
|
shun-iwasawa |
27b0cf |
const TPixel32 &color) {}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Campbell Barton |
b3bd84 |
static TPoint nearestInk(const TRasterCM32P &r, const TPoint &p, int ray) {
|
|
Shinya Kitaoka |
120a6e |
int i, j;
|
|
Shinya Kitaoka |
120a6e |
TPixelCM32 *buf = (TPixelCM32 *)r->getRawData();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
for (j = std::max(p.y - ray, 0); j <= std::min(p.y + ray, r->getLy() - 1);
|
|
Shinya Kitaoka |
120a6e |
j++)
|
|
Shinya Kitaoka |
120a6e |
for (i = std::max(p.x - ray, 0); i <= std::min(p.x + ray, r->getLx() - 1);
|
|
Shinya Kitaoka |
120a6e |
i++)
|
|
Shinya Kitaoka |
120a6e |
if (!(buf + j * r->getWrap() + i)->isPurePaint()) return TPoint(i, j);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
return TPoint(-1, -1);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void inkFill(const TRasterCM32P &r, const TPoint &pin, int ink, int searchRay,
|
|
Shinya Kitaoka |
120a6e |
TTileSaverCM32 *saver, TRect *insideRect) {
|
|
Shinya Kitaoka |
120a6e |
r->lock();
|
|
Shinya Kitaoka |
120a6e |
TPixelCM32 *pixels = (TPixelCM32 *)r->getRawData();
|
|
Shinya Kitaoka |
120a6e |
int oldInk;
|
|
Shinya Kitaoka |
120a6e |
TPoint p = pin;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if ((pixels + p.y * r->getWrap() + p.x)->isPurePaint() &&
|
|
Shinya Kitaoka |
120a6e |
(searchRay == 0 || (p = nearestInk(r, p, searchRay)) == TPoint(-1, -1))) {
|
|
Shinya Kitaoka |
120a6e |
r->unlock();
|
|
Shinya Kitaoka |
120a6e |
return;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
TPixelCM32 *pix = pixels + (p.y * r->getWrap() + p.x);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (pix->getInk() == ink) {
|
|
Shinya Kitaoka |
120a6e |
r->unlock();
|
|
Shinya Kitaoka |
120a6e |
return;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
oldInk = pix->getInk();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
std::stack<tpoint> seeds;</tpoint>
|
|
Shinya Kitaoka |
120a6e |
seeds.push(p);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
while (!seeds.empty()) {
|
|
Shinya Kitaoka |
120a6e |
p = seeds.top();
|
|
Shinya Kitaoka |
120a6e |
seeds.pop();
|
|
Shinya Kitaoka |
120a6e |
if (!r->getBounds().contains(p)) continue;
|
|
Shinya Kitaoka |
120a6e |
if (insideRect && !insideRect->contains(p)) continue;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TPixelCM32 *pix = pixels + (p.y * r->getWrap() + p.x);
|
|
Shinya Kitaoka |
120a6e |
if (pix->isPurePaint() || pix->getInk() != oldInk) continue;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (saver) saver->save(p);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
pix->setInk(ink);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
seeds.push(TPoint(p.x - 1, p.y - 1));
|
|
Shinya Kitaoka |
120a6e |
seeds.push(TPoint(p.x - 1, p.y));
|
|
Shinya Kitaoka |
120a6e |
seeds.push(TPoint(p.x - 1, p.y + 1));
|
|
Shinya Kitaoka |
120a6e |
seeds.push(TPoint(p.x, p.y - 1));
|
|
Shinya Kitaoka |
120a6e |
seeds.push(TPoint(p.x, p.y + 1));
|
|
Shinya Kitaoka |
120a6e |
seeds.push(TPoint(p.x + 1, p.y - 1));
|
|
Shinya Kitaoka |
120a6e |
seeds.push(TPoint(p.x + 1, p.y));
|
|
Shinya Kitaoka |
120a6e |
seeds.push(TPoint(p.x + 1, p.y + 1));
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
r->unlock();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
//-----------------------------------------------------------------------------
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
void fullColorFill(const TRaster32P &ras, const FillParameters ¶ms,
|
|
shun-iwasawa |
14c787 |
TTileSaverFullColor *saver) {
|
|
shun-iwasawa |
14c787 |
int oldy, xa, xb, xc, xd, dy, oldxd, oldxc;
|
|
shun-iwasawa |
14c787 |
TPixel32 *pix, *limit, *pix0, *oldpix;
|
|
shun-iwasawa |
14c787 |
int x = params.m_p.x, y = params.m_p.y;
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
TRect bbbox = ras->getBounds();
|
|
shun-iwasawa |
14c787 |
if (!bbbox.contains(params.m_p)) return;
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
TPixel32 clickedPosColor = *(ras->pixels(y) + x);
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
TPaletteP plt = params.m_palette;
|
|
shun-iwasawa |
14c787 |
TPixel32 color = plt->getStyle(params.m_styleId)->getMainColor();
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
if (clickedPosColor == color) return;
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
int fillDepth =
|
|
shun-iwasawa |
14c787 |
params.m_shiftFill ? params.m_maxFillDepth : params.m_minFillDepth;
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
assert(fillDepth >= 0 && fillDepth < 16);
|
|
shun-iwasawa |
14c787 |
TPointD m_firstPoint, m_clickPoint;
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
// convert fillDepth range from [0 - 15] to [0 - 255]
|
|
shun-iwasawa |
14c787 |
fillDepth = (fillDepth << 4) | fillDepth;
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
std::stack<fillseed> seeds;</fillseed>
|
|
shun-iwasawa |
14c787 |
std::map<int, int="" std::vector<std::pair<int,="">>> segments;</int,>
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
fullColorFindSegment(ras, params.m_p, xa, xb, color, clickedPosColor,
|
|
shun-iwasawa |
14c787 |
fillDepth);
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
segments[y].push_back(std::pair<int, int="">(xa, xb));</int,>
|
|
shun-iwasawa |
14c787 |
seeds.push(FillSeed(xa, xb, y, 1));
|
|
shun-iwasawa |
14c787 |
seeds.push(FillSeed(xa, xb, y, -1));
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
while (!seeds.empty()) {
|
|
shun-iwasawa |
14c787 |
FillSeed fs = seeds.top();
|
|
shun-iwasawa |
14c787 |
seeds.pop();
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
xa = fs.m_xa;
|
|
shun-iwasawa |
14c787 |
xb = fs.m_xb;
|
|
shun-iwasawa |
14c787 |
oldy = fs.m_y;
|
|
shun-iwasawa |
14c787 |
dy = fs.m_dy;
|
|
shun-iwasawa |
14c787 |
y = oldy + dy;
|
|
shun-iwasawa |
14c787 |
// continue if the fill runs over image bounding
|
|
shun-iwasawa |
14c787 |
if (y > bbbox.y1 || y < bbbox.y0) continue;
|
|
shun-iwasawa |
14c787 |
// left end of the pixels to be filled
|
|
shun-iwasawa |
14c787 |
pix = pix0 = ras->pixels(y) + xa;
|
|
shun-iwasawa |
14c787 |
// right end of the pixels to be filled
|
|
shun-iwasawa |
14c787 |
limit = ras->pixels(y) + xb;
|
|
shun-iwasawa |
14c787 |
// left end of the fill seed pixels
|
|
shun-iwasawa |
14c787 |
oldpix = ras->pixels(oldy) + xa;
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
x = xa;
|
|
shun-iwasawa |
14c787 |
oldxd = (std::numeric_limits<int>::min)();</int>
|
|
shun-iwasawa |
14c787 |
oldxc = (std::numeric_limits<int>::max)();</int>
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
// check pixels to right
|
|
shun-iwasawa |
14c787 |
while (pix <= limit) {
|
|
shun-iwasawa |
14c787 |
bool test = false;
|
|
shun-iwasawa |
14c787 |
// check if the target is already in the range to be filled
|
|
shun-iwasawa |
14c787 |
if (segments.find(y) != segments.end())
|
|
shun-iwasawa |
14c787 |
test = isPixelInSegment(segments[y], x);
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
if (*pix != color && !test &&
|
|
shun-iwasawa |
14c787 |
floodCheck(clickedPosColor, pix, oldpix, fillDepth)) {
|
|
shun-iwasawa |
14c787 |
// compute horizontal range to be filled
|
|
shun-iwasawa |
14c787 |
fullColorFindSegment(ras, TPoint(x, y), xc, xd, color, clickedPosColor,
|
|
shun-iwasawa |
14c787 |
fillDepth);
|
|
shun-iwasawa |
14c787 |
// insert segment to be filled
|
|
shun-iwasawa |
14c787 |
insertSegment(segments[y], std::pair<int, int="">(xc, xd));</int,>
|
|
shun-iwasawa |
14c787 |
// create new fillSeed to invert direction, if needed
|
|
shun-iwasawa |
14c787 |
if (xc < xa) seeds.push(FillSeed(xc, xa - 1, y, -dy));
|
|
shun-iwasawa |
14c787 |
if (xd > xb) seeds.push(FillSeed(xb + 1, xd, y, -dy));
|
|
shun-iwasawa |
14c787 |
if (oldxd >= xc - 1)
|
|
shun-iwasawa |
14c787 |
oldxd = xd;
|
|
shun-iwasawa |
14c787 |
else {
|
|
shun-iwasawa |
14c787 |
if (oldxd >= 0) seeds.push(FillSeed(oldxc, oldxd, y, dy));
|
|
shun-iwasawa |
14c787 |
oldxc = xc;
|
|
shun-iwasawa |
14c787 |
oldxd = xd;
|
|
shun-iwasawa |
14c787 |
}
|
|
shun-iwasawa |
14c787 |
// jump to the next pixel to the right end of the range
|
|
shun-iwasawa |
14c787 |
pix += xd - x + 1;
|
|
shun-iwasawa |
14c787 |
oldpix += xd - x + 1;
|
|
shun-iwasawa |
14c787 |
x += xd - x + 1;
|
|
shun-iwasawa |
14c787 |
} else {
|
|
shun-iwasawa |
14c787 |
pix++;
|
|
shun-iwasawa |
14c787 |
oldpix++, x++;
|
|
shun-iwasawa |
14c787 |
}
|
|
shun-iwasawa |
14c787 |
}
|
|
shun-iwasawa |
14c787 |
// insert filled range as new fill seed
|
|
shun-iwasawa |
14c787 |
if (oldxd > 0) seeds.push(FillSeed(oldxc, oldxd, y, dy));
|
|
shun-iwasawa |
14c787 |
}
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
// pixels are actually filled here
|
|
shun-iwasawa |
14c787 |
TPixel32 premultiColor = premultiply(color);
|
|
shun-iwasawa |
14c787 |
|
|
shun-iwasawa |
14c787 |
std::map<int, int="" std::vector<std::pair<int,="">>>::iterator it;</int,>
|
|
shun-iwasawa |
14c787 |
for (it = segments.begin(); it != segments.end(); it++) {
|
|
shun-iwasawa |
443318 |
TPixel32 *line = ras->pixels(it->first);
|
|
shun-iwasawa |
443318 |
TPixel32 *refLine = 0;
|
|
shun-iwasawa |
14c787 |
std::vector<std::pair<int, int="">> segmentVector = it->second;</std::pair<int,>
|
|
shun-iwasawa |
14c787 |
for (int i = 0; i < (int)segmentVector.size(); i++) {
|
|
shun-iwasawa |
14c787 |
std::pair<int, int=""> segment = segmentVector[i];</int,>
|
|
shun-iwasawa |
14c787 |
if (segment.second >= segment.first) {
|
|
shun-iwasawa |
14c787 |
pix = line + segment.first;
|
|
shun-iwasawa |
14c787 |
if (saver) {
|
|
shun-iwasawa |
14c787 |
saver->save(
|
|
shun-iwasawa |
14c787 |
TRect(segment.first, it->first, segment.second, it->first));
|
|
shun-iwasawa |
14c787 |
}
|
|
shun-iwasawa |
14c787 |
int n;
|
|
shun-iwasawa |
14c787 |
for (n = 0; n < segment.second - segment.first + 1; n++, pix++) {
|
|
shun-iwasawa |
14c787 |
if (clickedPosColor.m == 0)
|
|
shun-iwasawa |
14c787 |
*pix = pix->m == 0 ? color : overPix(color, *pix);
|
|
shun-iwasawa |
14c787 |
else if (color.m == 0 || color.m == 255) // used for erasing area
|
|
shun-iwasawa |
14c787 |
*pix = color;
|
|
shun-iwasawa |
14c787 |
else
|
|
shun-iwasawa |
14c787 |
*pix = overPix(*pix, premultiColor);
|
|
shun-iwasawa |
14c787 |
}
|
|
shun-iwasawa |
14c787 |
}
|
|
shun-iwasawa |
14c787 |
}
|
|
shun-iwasawa |
14c787 |
}
|
|
shun-iwasawa |
14c787 |
}
|