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
}