Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <stack></stack>
Toshihiro Shimizu 890ddd
#include <time.h></time.h>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "stdfx.h"
Toshihiro Shimizu 890ddd
#include "tsystem.h"
Toshihiro Shimizu 890ddd
#include "tconvert.h"
Toshihiro Shimizu 890ddd
#include "trop.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/* Riferimenti:
Shinya Kitaoka 120a6e
[1] "Filling a region in a frame buffer", Ken Fishkin, su Graphics Gems vol.1,
Shinya Kitaoka 120a6e
pag 278;
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TODO
Toshihiro Shimizu 890ddd
// v integrare in zcomp
Toshihiro Shimizu 890ddd
// v aggiungere: selezioni multiple, antialias, feather, .
Shinya Kitaoka 120a6e
// v aggiungere: gestione del mouse, indicatore del colore del pixel
Shinya Kitaoka 120a6e
// selezionato, media sui vicini del pixel selezionato
Toshihiro Shimizu 890ddd
// . maglass
Toshihiro Shimizu 890ddd
// . verifiche ed ottimizzazioni
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {}  // anonymous namespace
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static int invocazioni = 0;  // tmp: numero di invocazioni della MagicWand
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Shadow Segment
Shinya Kitaoka 120a6e
// "Ombra" proiettata da una riga di pixel idonei sulle righe adiacenti
Shinya Kitaoka 120a6e
// superiore ed inferiore; vedi [1].
Shinya Kitaoka 120a6e
class ShadowSegment {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  ShadowSegment(int Lx, int Rx, int pLx, int pRx, int y, int dir)
Shinya Kitaoka 120a6e
      : m_lx(Lx), m_rx(Rx), m_pLx(pLx), m_pRx(pRx), m_y(y), m_dir(dir) {}
Shinya Kitaoka 120a6e
  int m_rx,   // Right endpoint
Shinya Kitaoka 120a6e
      m_lx,   // Left endpoint
Shinya Kitaoka 120a6e
      m_pRx,  // parent Right endpoint
Shinya Kitaoka 120a6e
      m_pLx,  // parent Left endpoint
Shinya Kitaoka 120a6e
      m_y,    // this segment line
Shinya Kitaoka 120a6e
      m_dir;  // upward, downward
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Stack per la memorizzazione dei segmenti.
Toshihiro Shimizu 890ddd
typedef std::stack<shadowsegment> ShadowSegmentStack;</shadowsegment>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class MagicWandFx : public TStandardRasterFx {
Shinya Kitaoka 120a6e
  FX_PLUGIN_DECLARATION(MagicWandFx)
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRasterFxPort m_input;
Shinya Kitaoka 120a6e
  TDoubleParamP m_tolerance;   // tolleranza
Shinya Kitaoka 120a6e
  TDoubleParamP m_blurRadius;  // ampiezza del campione per il SEED
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointParamP m_point;       // coordinate del SEED (passate da zviewer)
Shinya Kitaoka 120a6e
  TBoolParamP m_contiguous;   // selezione di regioni non connesse alla regione
Shinya Kitaoka 120a6e
                              // contentente il SEED
Shinya Kitaoka 120a6e
  TBoolParamP m_antialiased;  // applicazione dell'antialiasing
Shinya Kitaoka 120a6e
  TBoolParamP m_euclideanD;   // funzione alternativa per il calcolo della
Shinya Kitaoka 120a6e
                              // "similitudine" tra punti
Shinya Kitaoka 120a6e
  TBoolParamP m_preMolt;      // premoltiplicazione
Shinya Kitaoka 120a6e
  TBoolParamP m_isShiftPressed;  // per le selezioni multiple: SUB
Shinya Kitaoka 120a6e
  TBoolParamP m_isAltPressed;    // per le selezioni multiple: ADD
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  MagicWandFx()
Shinya Kitaoka 120a6e
      : m_tolerance(15.0)
Shinya Kitaoka 120a6e
      , m_blurRadius(0.0)
Shinya Kitaoka 120a6e
      , m_point(TPointD(0, 0))
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    m_contiguous     = TBoolParamP(true);
Shinya Kitaoka 120a6e
    m_antialiased    = TBoolParamP(true);
Shinya Kitaoka 120a6e
    m_euclideanD     = TBoolParamP(true);
Shinya Kitaoka 120a6e
    m_preMolt        = TBoolParamP(true);
Shinya Kitaoka 120a6e
    m_isShiftPressed = TBoolParamP(false);
Shinya Kitaoka 120a6e
    m_isAltPressed   = TBoolParamP(false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    addParam("Tolerance", m_tolerance);
Shinya Kitaoka 120a6e
    addParam("Feather", m_blurRadius);
Shinya Kitaoka 120a6e
    addParam("Point", m_point);
Shinya Kitaoka 120a6e
    addParam("Contiguous", m_contiguous);
Shinya Kitaoka 120a6e
    addParam("Antialias", m_antialiased);
Shinya Kitaoka 120a6e
    addParam("EuclideanD", m_euclideanD);
Shinya Kitaoka 120a6e
    addParam("PreMultiply", m_preMolt);
Shinya Kitaoka 120a6e
    addParam("isShiftPressed", m_isShiftPressed);
Shinya Kitaoka 120a6e
    addParam("isAltPressed", m_isAltPressed);
Shinya Kitaoka 120a6e
    addInputPort("Source", m_input);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_tolerance->setValueRange(0, 255);
Shinya Kitaoka 120a6e
    m_blurRadius->setValueRange(0, 100);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ~MagicWandFx(){};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRect getInvalidRect(const TRect &max);
Shinya Kitaoka 120a6e
  void doCompute(TTile &tile, double frame, const TRasterFxRenderInfo *ri);
Shinya Kitaoka 120a6e
  void doMagicWand(TTile &tile, double frame, const TRasterFxRenderInfo *ri);
Shinya Kitaoka 120a6e
  void EnqueueSegment(int num, int dir, int pLx, int pRx, int Lx, int Rx,
Shinya Kitaoka 120a6e
                      int y);
Shinya Kitaoka 120a6e
  bool pixelProcessor(TPixel32 *testPix, TPixelGR8 *maskPix);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool getBBox(double frame, TRectD &rect, TPixel32 &bgColor) {
Shinya Kitaoka 120a6e
    return m_input->getBBox(frame, rect, bgColor);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRasterGR8P m_maskGR8;  // maschera
Shinya Kitaoka 120a6e
  TPixel32 *m_pickedPix;  // puntatore al pixel SEED
Shinya Kitaoka 120a6e
  TPixelGR8 *m_maskPickedPix;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int m_imageHeigth;  // altezza del raster
Shinya Kitaoka 120a6e
  int m_imageWidth;   // larghezza del raster
Shinya Kitaoka 120a6e
  double m_tol;   // le uso per evitare di dover richiamare la funzione getValue
Shinya Kitaoka 120a6e
                  // per ogni punto: sistemare?
Shinya Kitaoka 120a6e
  int m_cont;     // le uso per evitare di dover richiamare la funzione getValue
Shinya Kitaoka 120a6e
                  // per ogni punto: sistemare?
Shinya Kitaoka 120a6e
  bool m_antial;  // le uso per evitare di dover richiamare la funzione getValue
Shinya Kitaoka 120a6e
                  // per ogni punto: sistemare?
Shinya Kitaoka 120a6e
  bool m_euclid;  // le uso per evitare di dover richiamare la funzione getValue
Shinya Kitaoka 120a6e
                  // per ogni punto: sistemare?
Shinya Kitaoka 120a6e
  bool m_add;
Shinya Kitaoka 120a6e
  bool m_sub;
Shinya Kitaoka 120a6e
  int m_id_invocazione;          // contatore delle invocazioni
Shinya Kitaoka 120a6e
  ShadowSegmentStack m_sSStack;  // stack dei segmenti shadow
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
const int EmptyPixel = 0;
Shinya Kitaoka 120a6e
const int FullPixel  = 255;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// tmp: per l'analisi delle prestazioni
Toshihiro Shimizu 890ddd
int pixelProcessed;
Toshihiro Shimizu 890ddd
int pixelMasked;
Toshihiro Shimizu 890ddd
int shadowEnqueued;
Toshihiro Shimizu 890ddd
int pixelReprocessed;
Toshihiro Shimizu 890ddd
int shadowOutOfBorder;
Toshihiro Shimizu 890ddd
bool maskValue;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool MagicWandFx::pixelProcessor(TPixel32 *testPix, TPixelGR8 *maskPix) {
Shinya Kitaoka 120a6e
  pixelProcessed++;
Shinya Kitaoka 120a6e
  unsigned int maskValue = 0;
Shinya Kitaoka 120a6e
  double diff            = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // valuto la distanza tra il testPix ed il SEED e la metto in diff
Shinya Kitaoka 120a6e
  if (m_euclid) {
Shinya Kitaoka 120a6e
    // calcolo la Distanza Euclidea tra i punti nello spazio RGB
Shinya Kitaoka 120a6e
    diff = sqrt((m_pickedPix->r - testPix->r) * (m_pickedPix->r - testPix->r) +
Shinya Kitaoka 120a6e
                (m_pickedPix->g - testPix->g) * (m_pickedPix->g - testPix->g) +
Shinya Kitaoka 120a6e
                (m_pickedPix->b - testPix->b) * (m_pickedPix->b - testPix->b));
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // GIMP-like: confronto la tolleranza con il massimo tra gli scarti delle
Shinya Kitaoka 120a6e
    // componenti
Shinya Kitaoka 120a6e
    diff                       = abs(m_pickedPix->r - testPix->r);
Shinya Kitaoka 120a6e
    double diffNext            = abs(m_pickedPix->g - testPix->g);
Shinya Kitaoka 120a6e
    if (diffNext >= diff) diff = diffNext;
Shinya Kitaoka 120a6e
    diffNext                   = abs(m_pickedPix->b - testPix->b);
Shinya Kitaoka 120a6e
    if (diffNext >= diff) diff = diffNext;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (diff <= m_tol)
Shinya Kitaoka 120a6e
    maskValue = FullPixel;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    maskValue = EmptyPixel;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (maskValue) {
Shinya Kitaoka 120a6e
    // il pixel soddisfa il criterio di compatibilita
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_add) {
Shinya Kitaoka 120a6e
      // sto aggiungendo selezioni
Shinya Kitaoka 120a6e
      if (testPix->m != EmptyPixel) {
Shinya Kitaoka 120a6e
        pixelReprocessed++;
Shinya Kitaoka 120a6e
        return false;
Shinya Kitaoka 120a6e
      }  // gia' trattato
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      //* DECIDERE SE VOGLIO CHE LA SELEZIONE INTERESSI AREE GIA' SELEZIONATE IN
Shinya Kitaoka 38fd86
      // PRECEDENZA
Shinya Kitaoka 120a6e
      //      if (maskPix->value == EmptyPixel) { //pixel c-compatibile, non
Shinya Kitaoka 120a6e
      //      gia' mascherato
Shinya Kitaoka 120a6e
      testPix->m     = maskValue;  // set(mV)m
Shinya Kitaoka 120a6e
      maskPix->value = maskValue;  // set(mV)a
Shinya Kitaoka 120a6e
      pixelMasked++;
Shinya Kitaoka 120a6e
      //      } else { // pixel c-compatibile gia' mascherato precedentemente
Shinya Kitaoka 120a6e
      //               testPix->m = maskValue;  // set(mV)m
Shinya Kitaoka 120a6e
      //     }
Shinya Kitaoka 120a6e
    } else if (m_sub) {
Shinya Kitaoka 120a6e
      // sto togliendo selezioni
Shinya Kitaoka 120a6e
      if (testPix->m != EmptyPixel) return false;  // gia' trattato
Shinya Kitaoka 120a6e
      testPix->m     = maskValue;                  // set(mV)m
Shinya Kitaoka 120a6e
      maskPix->value = EmptyPixel;                 // set(0)a
Shinya Kitaoka 120a6e
    } else {                                       // prima selezione
Shinya Kitaoka 120a6e
      if (testPix->m != EmptyPixel) return false;  // gia' trattato
Shinya Kitaoka 120a6e
      testPix->m     = maskValue;                  // set(mV)m
Shinya Kitaoka 120a6e
      maskPix->value = maskValue;                  // set(mV)a
Shinya Kitaoka 120a6e
      pixelMasked++;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return true;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
}  // pixelProcessor
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// [1]: aggiunge le ombre necessarie alla pila.
Shinya Kitaoka 120a6e
void MagicWandFx::EnqueueSegment(int num, int dir, int pLx, int pRx, int Lx,
Shinya Kitaoka 120a6e
                                 int Rx, int y) {
Shinya Kitaoka 120a6e
  int pushRx = Rx + 1;
Shinya Kitaoka 120a6e
  int pushLx = Lx + 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //  TSystem::outputDebug("[MWfx("+toString(m_id_invocazione)+":"+toString(num)+")
Shinya Kitaoka 120a6e
  //  1>]\tStack Size:"+toString((int)
Shinya Kitaoka 120a6e
  //  m_sSStack.size())+"\tLx:"+toString(Lx)+"\tRx:"+toString(Rx)+"\tpLx:"+toString(pushLx)+"\tpRx:"+toString(pushRx)+"\ty:"+toString(y)+"\tdir:"+toString(dir)+"\n");
Shinya Kitaoka 120a6e
  assert((Lx <= Rx) && (pushLx <= pushRx) && (Lx >= 0));
Shinya Kitaoka 120a6e
  m_sSStack.push(ShadowSegment(Lx, Rx, pushLx, pushRx, (y + dir), dir));
Shinya Kitaoka 120a6e
  shadowEnqueued++;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (Rx > pRx) {  // U-turn a destra
Shinya Kitaoka 120a6e
                   //  TSystem::outputDebug("[MWfx("+toString(m_id_invocazione)+":"+toString(num)+")
Shinya Kitaoka 120a6e
                   //  2>]\tStack Size:"+toString((int)
Shinya Kitaoka 120a6e
                   //  m_sSStack.size())+"\tLx:"+toString(pRx+1)+"\tRx:"+toString(Rx)+"\tpLx:"+toString(pushLx)+"\tpRx:"+toString(pushRx)+"\ty:"+toString(y-dir)+"\tdir:"+toString(dir)+"\n");
Shinya Kitaoka 120a6e
    assert(((pRx + 1) <= (Rx)) && (pushLx <= pushRx) && ((pRx + 1) >= 0));
Shinya Kitaoka 120a6e
    m_sSStack.push(
Shinya Kitaoka 120a6e
        ShadowSegment((pRx + 1), Rx, pushLx, pushRx, (y - dir), (-dir)));
Shinya Kitaoka 120a6e
    shadowEnqueued++;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (Lx < pLx) {  // U-turn a sinistra
Shinya Kitaoka 120a6e
                   //    TSystem::outputDebug("[MWfx("+toString(m_id_invocazione)+":"+toString(num)+")
Shinya Kitaoka 120a6e
                   //    3>]\tStack Size:"+toString((int)
Shinya Kitaoka 120a6e
                   //    m_sSStack.size())+"\tLx:"+toString(Lx)+"\tRx:"+toString(pLx-1)+"\tpLx:"+toString(pushLx)+"\tpRx:"+toString(pushRx)+"\ty:"+toString(y-dir)+"\tdir:"+toString(dir)+"\n");
Shinya Kitaoka 120a6e
    assert(((Lx) <= (pLx - 1)) && (pushLx <= pushRx) && (Lx >= 0));
Shinya Kitaoka 120a6e
    m_sSStack.push(
Shinya Kitaoka 120a6e
        ShadowSegment(Lx, (pLx - 1), pushLx, pushRx, (y - dir), (-dir)));
Shinya Kitaoka 120a6e
    shadowEnqueued++;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  // W-Turn = 2 U-Turn
Shinya Kitaoka 120a6e
}  // EnqueueSegment
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void MagicWandFx::doMagicWand(TTile &tile, double frame,
Shinya Kitaoka 120a6e
                              const TRasterFxRenderInfo *ri) {
Shinya Kitaoka 120a6e
  clock_t start_time = clock();  // debug
Shinya Kitaoka 120a6e
  clock_t stop_time;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  invocazioni++;
Shinya Kitaoka 120a6e
  m_id_invocazione = invocazioni;
Shinya Kitaoka 120a6e
  m_tol            = m_tolerance->getValue(frame);
Shinya Kitaoka 120a6e
  m_antial         = m_antialiased->getValue();
Shinya Kitaoka 120a6e
  m_euclid         = m_euclideanD->getValue();  // temporaneo?
Shinya Kitaoka 120a6e
  m_cont = m_contiguous->getValue();  // selezione di aree cromaticamente
Shinya Kitaoka 120a6e
                                      // compatibili ma non contigue: Selezione
Shinya Kitaoka 120a6e
                                      // ByColor
Shinya Kitaoka 120a6e
  m_add = m_isShiftPressed->getValue();
Shinya Kitaoka 120a6e
  m_sub = m_isAltPressed->getValue();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  tile.getRaster()->lock();
Shinya Kitaoka 120a6e
  TRaster32P ras32 = tile.getRaster();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPixel32 vPixel;
Shinya Kitaoka 120a6e
  TPixel32 *tmpPix;
Shinya Kitaoka 120a6e
  TPixel32 *rowStart;
Shinya Kitaoka 120a6e
  TPixelGR8 *maskRowStart;
Shinya Kitaoka 120a6e
  TPixelGR8 *maskPix;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (ras32) {
Shinya Kitaoka 120a6e
    pixelProcessed    = 0;
Shinya Kitaoka 120a6e
    pixelMasked       = 1;
Shinya Kitaoka 120a6e
    shadowEnqueued    = 2;
Shinya Kitaoka 120a6e
    pixelReprocessed  = 0;
Shinya Kitaoka 120a6e
    shadowOutOfBorder = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_imageWidth  = ras32->getLx();
Shinya Kitaoka 120a6e
    m_imageHeigth = ras32->getLy();
Shinya Kitaoka 120a6e
    // assert(m_imageWidth == 800);
Shinya Kitaoka 120a6e
    assert(m_imageHeigth <= 600);
Shinya Kitaoka 120a6e
    int lx = m_imageWidth;
Shinya Kitaoka 120a6e
    int ly = m_imageHeigth;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!m_maskGR8) {
Shinya Kitaoka 120a6e
      // prima esecuzione creo il raster gr8 x la maschera e azzero gli alpha
Shinya Kitaoka 120a6e
      TRectD bBoxD;
Shinya Kitaoka 120a6e
      TPixel32 bgColor;
Shinya Kitaoka 120a6e
      bool getBBoxOk = getBBox(frame, bBoxD, bgColor);
Shinya Kitaoka 120a6e
      assert(getBBoxOk);
Shinya Kitaoka 120a6e
      TRect bBoxI = convert(bBoxD);
Shinya Kitaoka 120a6e
      m_maskGR8   = TRasterGR8P(bBoxI.getLx(), bBoxI.getLy());
Shinya Kitaoka 120a6e
      m_maskGR8->clear();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    m_maskGR8->lock();
Shinya Kitaoka 120a6e
    // sono arrivato qui: sto verificando se serve davvero il gr8.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (int iy = 0; iy < m_imageHeigth; iy++) {  // y
Shinya Kitaoka 120a6e
      tmpPix = ras32->pixels(iy);
Shinya Kitaoka 120a6e
      for (int ix = 0; ix < m_imageWidth; ix++) {  // x
Shinya Kitaoka 120a6e
        tmpPix->m = EmptyPixel;
Shinya Kitaoka 120a6e
        tmpPix++;
Shinya Kitaoka 120a6e
      }  // x
Shinya Kitaoka 120a6e
    }    // y
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_add) {  // ho premuto Shift sto aggiungendo alla selezione
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    } else if (m_sub) {
Shinya Kitaoka 120a6e
      // ho premuto Alt sto sottraendo dalla selezione
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      // non ho premuto niente nuova selezione
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // ripulisco il canale alpha dell'immagine e la maschera
Shinya Kitaoka 120a6e
      for (int iy = 0; iy < m_imageHeigth; iy++) {
Shinya Kitaoka 120a6e
        tmpPix  = ras32->pixels(iy);
Shinya Kitaoka 120a6e
        maskPix = m_maskGR8->pixels(iy);
Shinya Kitaoka 120a6e
        for (int ix = 0; ix < m_imageWidth; ix++) {
Shinya Kitaoka 120a6e
          tmpPix->m = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          maskPix->value = EmptyPixel;
Shinya Kitaoka 120a6e
          tmpPix++;
Shinya Kitaoka 120a6e
          maskPix++;
Shinya Kitaoka 120a6e
        }  // x
Shinya Kitaoka 120a6e
      }    // y
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // trovo il pixel in X,Y soluzione temporanea in attesa della gestione del
Shinya Kitaoka 120a6e
    // mouse.
Shinya Kitaoka 120a6e
    // converto le coordinate mondo (-500;+500) in coordinate raster
Shinya Kitaoka 120a6e
    // (0;m_imageWidth);
Shinya Kitaoka 120a6e
    TPointD point = m_point->getValue(frame);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // coordinate dagli sliders
Shinya Kitaoka 120a6e
    //    int x = (int) (500+point.x)*m_imageWidth/1000; if (x>0) x--;
Shinya Kitaoka 120a6e
    //    int y = (int) (500+point.y)*m_imageHeigth/1000; if (y>0) y--;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // coordinate dalla ZViewer:leftButtonClick
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int x = tcrop((int)(point.x + m_imageWidth / 2), 0, (m_imageWidth - 1));
Shinya Kitaoka 120a6e
    int y = tcrop((int)(point.y + m_imageHeigth / 2), 0, (m_imageHeigth - 1));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TSystem::outputDebug("\n[MWfx(" + toString(m_id_invocazione) +
Shinya Kitaoka 120a6e
                         ")<begin>]\nSize:" + toString(m_imageWidth) + "x" +</begin>
Shinya Kitaoka 120a6e
                         toString(m_imageHeigth) + "\tx:" + toString(x) +
Shinya Kitaoka 120a6e
                         "\ty:" + toString(y) + "\tToll:" + toString(m_tol) +
Shinya Kitaoka 120a6e
                         /*      "\tRadius:" + toString(radius) +*/ (
Shinya Kitaoka 120a6e
                             (m_cont) ? "\tContiguous" : "\tNon Contiguous") +
Shinya Kitaoka 120a6e
                         ((m_antial) ? "\tAnti Aliased" : "\tAliased") +
Shinya Kitaoka 120a6e
                         ((m_euclid) ? "\tEuclidean\n" : "\tNon Euclidean\n"));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    lx = m_imageWidth;
Shinya Kitaoka 120a6e
    ly = m_imageHeigth;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_pickedPix     = ras32->pixels(y) + x;
Shinya Kitaoka 120a6e
    m_maskPickedPix = m_maskGR8->pixels(y) + x;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    pixelProcessed = 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_cont) {  // seleziono esclusivamente i pixel connessi al pixel SEED
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      //- ALGORITMO FLOOD FILL: GRAPHICS GEM 1 p.280
Shinya Kitaoka 120a6e
      //----------------------------------------
Shinya Kitaoka 120a6e
      int xAux, yAux, lxAux, rxAux, dirAux, pRxAux, pLxAux;
Shinya Kitaoka 120a6e
      bool inSpan = true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // trova Rx e Lx dello span contentente il SEED point
Shinya Kitaoka 120a6e
      int xCont = x;
Shinya Kitaoka 120a6e
      tmpPix    = m_pickedPix;      // puntatore al SEED
Shinya Kitaoka 120a6e
      maskPix   = m_maskPickedPix;  //******
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // cerco Lx
Shinya Kitaoka 120a6e
      maskValue  = pixelProcessor(tmpPix, maskPix);
Shinya Kitaoka 120a6e
      bool tmpMv = maskValue;
Shinya Kitaoka 120a6e
      while ((xCont >= 0) && (maskValue)) {
Shinya Kitaoka 120a6e
        tmpPix--;
Shinya Kitaoka 120a6e
        maskPix--;
Shinya Kitaoka 120a6e
        xCont--;
Shinya Kitaoka 120a6e
        if (xCont >= 0) maskValue = pixelProcessor(tmpPix, maskPix);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      if (tmpMv)
Shinya Kitaoka 120a6e
        lxAux = xCont + 1;
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        lxAux = xCont;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // cerco Rx
Shinya Kitaoka 120a6e
      tmpPix  = m_pickedPix;
Shinya Kitaoka 120a6e
      maskPix = m_maskPickedPix;  //******
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      xCont     = x;
Shinya Kitaoka 120a6e
      maskValue = tmpMv;
Shinya Kitaoka 120a6e
      while ((xCont < m_imageWidth) && (maskValue)) {
Shinya Kitaoka 120a6e
        tmpPix++;
Shinya Kitaoka 120a6e
        maskPix++;
Shinya Kitaoka 120a6e
        xCont++;
Shinya Kitaoka 120a6e
        if (xCont < m_imageWidth) maskValue = pixelProcessor(tmpPix, maskPix);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      if (tmpMv)
Shinya Kitaoka 120a6e
        rxAux = xCont - 1;
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        rxAux = xCont;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      assert((lxAux <= rxAux) && (lxAux >= 0));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // metto nella pila delle ombre la riga sopra e sotto quella contentente
Shinya Kitaoka 120a6e
      // il seed.
Shinya Kitaoka 120a6e
      //            TSystem::outputDebug("[MWfx("+toString(m_id_invocazione)+")]\tStack
Shinya Kitaoka 120a6e
      //            Size:"+toString((int)
Shinya Kitaoka 120a6e
      //            m_sSStack.size())+"\tLx:"+toString(lxAux)+"\tRx:"+toString(rxAux)+"\tpLx:"+toString(lxAux)+"\tpRx:"+toString(rxAux)+"\ty:"+toString(y+1)+"\tdir:"+toString(1)+"\n");
Shinya Kitaoka 120a6e
      m_sSStack.push(ShadowSegment(lxAux, rxAux, lxAux, rxAux, y + 1,
Shinya Kitaoka 120a6e
                                   +1));  // cerca in alto
Shinya Kitaoka 120a6e
                                          //            TSystem::outputDebug("[MWfx("+toString(m_id_invocazione)+")]\tStack
Shinya Kitaoka 120a6e
                                          //            Size:"+toString((int)
Shinya Kitaoka 120a6e
                                          //            m_sSStack.size())+"\tLx:"+toString(lxAux)+"\tRx:"+toString(rxAux)+"\tpLx:"+toString(lxAux)+"\tpRx:"+toString(rxAux)+"\ty:"+toString(y-1)+"\tdir:"+toString(-1)+"\n");
Shinya Kitaoka 120a6e
      m_sSStack.push(ShadowSegment(lxAux, rxAux, lxAux, rxAux, y - 1,
Shinya Kitaoka 120a6e
                                   -1));  // cerca in basso
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      while (!m_sSStack.empty()) {
Shinya Kitaoka 120a6e
        ShadowSegment sSegment = m_sSStack.top();
Shinya Kitaoka 120a6e
        m_sSStack.pop();
Shinya Kitaoka 120a6e
        //        TSystem::outputDebug("[MWfx("+toString(m_id_invocazione)+":0)
Shinya Kitaoka 120a6e
        //        >]\tStack Size:"+toString((int)
Shinya Kitaoka 120a6e
        //        m_sSStack.size())+"\tLx:"+toString(sSegment.m_lx)+"\tRx:"+toString(sSegment.m_rx)+"\tpLx:"+toString(sSegment.m_pLx)+"\tpRx:"+toString(sSegment.m_pRx)+"\ty:"+toString(sSegment.m_y)+"\tdir:"+toString(sSegment.m_dir)+"\n");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        dirAux = sSegment.m_dir;
Shinya Kitaoka 120a6e
        pRxAux = sSegment.m_pRx;
Shinya Kitaoka 120a6e
        pLxAux = sSegment.m_pLx;
Shinya Kitaoka 120a6e
        lxAux  = sSegment.m_lx;
Shinya Kitaoka 120a6e
        rxAux  = sSegment.m_rx;
Shinya Kitaoka 120a6e
        yAux   = sSegment.m_y;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if ((yAux < 0) || (yAux >= m_imageHeigth)) {
Shinya Kitaoka 120a6e
          shadowOutOfBorder++;
Shinya Kitaoka 120a6e
          continue;  // questo segmento sta fuori dal raster oppure l'ho gia'
Shinya Kitaoka 120a6e
                     // colorato: lo salto
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        assert((lxAux <= rxAux) && (pLxAux <= pRxAux));
Shinya Kitaoka 120a6e
        assert((m_sSStack.size() <= 1000));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        xAux = lxAux + 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        rowStart = ras32->pixels(yAux);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        maskRowStart = m_maskGR8->pixels(yAux);  //**
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        tmpPix  = rowStart + lxAux;
Shinya Kitaoka 120a6e
        maskPix = maskRowStart + lxAux;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        maskValue = pixelProcessor(tmpPix, maskPix);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        inSpan = (maskValue);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (maskValue) {  // il punto e' cromaticompatibile
Shinya Kitaoka 120a6e
          lxAux--;
Shinya Kitaoka 120a6e
          if (lxAux >= 0) {
Shinya Kitaoka 120a6e
            tmpPix--;
Shinya Kitaoka 120a6e
            maskPix--;
Shinya Kitaoka 120a6e
            maskValue = pixelProcessor(tmpPix, maskPix);
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
          while ((maskValue) &&
Shinya Kitaoka 120a6e
                 (lxAux >= 0)) {  // sto nello span E nell'immagine
Shinya Kitaoka 120a6e
            lxAux--;
Shinya Kitaoka 120a6e
            if (lxAux >= 0) {
Shinya Kitaoka 120a6e
              tmpPix--;
Shinya Kitaoka 120a6e
              maskPix--;
Shinya Kitaoka 120a6e
              maskValue = pixelProcessor(tmpPix, maskPix);
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
          }  // sto nello span E nell'immagine
Shinya Kitaoka 120a6e
        }    // il punto e' cromaticompatibile
Shinya Kitaoka 120a6e
        lxAux++;
Shinya Kitaoka 120a6e
        //        rowStart = ras32->pixels(yAux);
Shinya Kitaoka 120a6e
        while (xAux < m_imageWidth) {  // mi sposto a destra lungo la X
Shinya Kitaoka 120a6e
          if (inSpan) {
Shinya Kitaoka 120a6e
            tmpPix    = rowStart + xAux;
Shinya Kitaoka 120a6e
            maskPix   = maskRowStart + xAux;  //***
Shinya Kitaoka 120a6e
            maskValue = pixelProcessor(tmpPix, maskPix);
Shinya Kitaoka 120a6e
            if (maskValue) {  // case 1
Shinya Kitaoka 120a6e
                              // fa tutto nella pixel processor
Shinya Kitaoka 120a6e
            }                 // case 1
Shinya Kitaoka 120a6e
            else {            // case 2
Shinya Kitaoka 120a6e
              EnqueueSegment(1, dirAux, pLxAux, pRxAux, lxAux, (xAux - 1),
Shinya Kitaoka 120a6e
                             yAux);
Shinya Kitaoka 120a6e
              inSpan = false;
Shinya Kitaoka 120a6e
            }     // case 2
Shinya Kitaoka 120a6e
          }       // inSpan
Shinya Kitaoka 120a6e
          else {  // non ero nello span
Shinya Kitaoka 120a6e
            if (xAux > rxAux) break;
Shinya Kitaoka 120a6e
            tmpPix    = rowStart + xAux;
Shinya Kitaoka 120a6e
            maskPix   = maskRowStart + xAux;
Shinya Kitaoka 120a6e
            maskValue = pixelProcessor(tmpPix, maskPix);
Shinya Kitaoka 120a6e
            if (maskValue) {  // case 3
Shinya Kitaoka 120a6e
              inSpan = true;
Shinya Kitaoka 120a6e
              lxAux  = xAux;
Shinya Kitaoka 120a6e
            }       // case 3
Shinya Kitaoka 120a6e
            else {  // case 4
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
          }  // non ero nello span
Shinya Kitaoka 120a6e
          xAux++;
Shinya Kitaoka 120a6e
          //          TSystem::outputDebug("[MWfx("+toString(m_id_invocazione)+")]\tStack
Shinya Kitaoka 120a6e
          //          Size:"+toString((int)
Shinya Kitaoka 120a6e
          //          m_sSStack.size())+"\txAux:"+toString(xAux)+"\ty:"+toString(yAux)+"\n");
Shinya Kitaoka 120a6e
        }  // mi sposto a destra lungo la X: endloop 1
Shinya Kitaoka 120a6e
        if (inSpan) {
Shinya Kitaoka 120a6e
          EnqueueSegment(2, dirAux, pLxAux, pRxAux, lxAux, (xAux - 1), yAux);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }     // finche' la pila non e' vuota: endloop 2
Shinya Kitaoka 120a6e
    }       // if m_cont
Shinya Kitaoka 120a6e
    else {  // anche le regioni simili NON contigue: questo rimane anche in caso
Shinya Kitaoka 120a6e
            // di modifica della parte m_cont
Shinya Kitaoka 120a6e
      for (int iy = 0; iy < m_imageHeigth; iy++) {
Shinya Kitaoka 120a6e
        tmpPix  = ras32->pixels(iy);
Shinya Kitaoka 120a6e
        maskPix = m_maskGR8->pixels(iy);
Shinya Kitaoka 120a6e
        for (int ix = 0; ix < m_imageWidth; ix++) {
Shinya Kitaoka 120a6e
          maskValue = pixelProcessor(tmpPix, maskPix);
Shinya Kitaoka 120a6e
          //                 if (maskValue) { } // if// il colore e' simile =>
Shinya Kitaoka 120a6e
          //                 va incluso nella selezione // fa tutto nella pixel
Shinya Kitaoka 120a6e
          //                 processor
Shinya Kitaoka 120a6e
          tmpPix++;
Shinya Kitaoka 120a6e
          maskPix++;
Shinya Kitaoka 120a6e
        }  // ix
Shinya Kitaoka 120a6e
      }    // iy
Shinya Kitaoka 120a6e
    }      // else m_cont
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int blurRadius = (int)(m_blurRadius->getValue(frame));
Shinya Kitaoka 120a6e
    if ((m_antial) && (blurRadius < 2)) blurRadius = 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (blurRadius > 0)
Shinya Kitaoka 120a6e
      TRop::blur(m_maskGR8, m_maskGR8, (blurRadius + 1), 0, 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // copio la maschera sull'alpha channel dell'immagine
Shinya Kitaoka 120a6e
    // lo faccio a mano chiedere se esiste una funziona apposita
Shinya Kitaoka 120a6e
    for (iy = 0; iy < m_imageHeigth; iy++) {
Shinya Kitaoka 120a6e
      tmpPix  = ras32->pixels(iy);
Shinya Kitaoka 120a6e
      maskPix = m_maskGR8->pixels(iy);
Shinya Kitaoka 120a6e
      for (int ix = 0; ix < m_imageWidth; ix++) {
Shinya Kitaoka 120a6e
        tmpPix->m = maskPix->value;
Shinya Kitaoka 120a6e
        tmpPix++;
Shinya Kitaoka 120a6e
        maskPix++;
Shinya Kitaoka 120a6e
      }  // ix
Shinya Kitaoka 120a6e
    }    // iy
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_preMolt->getValue()) TRop::premultiply(ras32);
Shinya Kitaoka 120a6e
    stop_time     = clock();
Shinya Kitaoka 120a6e
    double durata = (double)(stop_time - start_time) / CLOCKS_PER_SEC;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TSystem::outputDebug(
Shinya Kitaoka 120a6e
        "\n#Pixel:\t" + toString(m_imageWidth * m_imageHeigth) + "\nProc:\t" +
Shinya Kitaoka 120a6e
        toString(pixelProcessed) + "\t[" +
Shinya Kitaoka 120a6e
        toString((pixelProcessed * 100 / (m_imageWidth * m_imageHeigth))) +
Shinya Kitaoka 120a6e
        "%t]" + "\nMask:\t" + toString(pixelMasked) + "\t[" +
Shinya Kitaoka 120a6e
        toString((pixelMasked * 100 / (m_imageWidth * m_imageHeigth))) + "%t]" +
Shinya Kitaoka 120a6e
        "\t[" + toString((pixelMasked * 100 / (pixelProcessed))) + "%p]" +
Shinya Kitaoka 120a6e
        "\nEnqu:\t" + toString(shadowEnqueued) + "\nRepr:\t" +
Shinya Kitaoka 120a6e
        toString(pixelReprocessed) + "\t[" +
Shinya Kitaoka 120a6e
        toString((pixelReprocessed * 100 / (m_imageWidth * m_imageHeigth))) +
Shinya Kitaoka 120a6e
        "%t]" + "\t[" + toString((pixelReprocessed * 100 / (pixelProcessed))) +
Shinya Kitaoka 120a6e
        "%p]" + "\nOutB:\t" + toString(shadowOutOfBorder) + "\t[" +
Shinya Kitaoka 120a6e
        toString((shadowOutOfBorder * 100 / (shadowEnqueued))) + "%t]" +
Shinya Kitaoka 120a6e
        "\nTime:\t" + toString(durata, 3) + " sec\n[MagicWandFX <end>]\n");</end>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  }  // if (ras32)
Shinya Kitaoka 120a6e
  else {
Shinya Kitaoka 120a6e
    TRasterGR8P rasGR8 = tile.getRaster();
Shinya Kitaoka 120a6e
    if (rasGR8) {
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  tile.getRaster()->unlock();
Shinya Kitaoka 120a6e
  m_maskGR8->unlock();
Shinya Kitaoka 120a6e
}  // doMagicWand
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void MagicWandFx::doCompute(TTile &tile, double frame,
Shinya Kitaoka 120a6e
                            const TRasterFxRenderInfo *ri) {
Shinya Kitaoka 120a6e
  if (!m_input.isConnected()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_input->compute(tile, frame, ri);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  doMagicWand(tile, frame, ri);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRect MagicWandFx::getInvalidRect(const TRect &max) { return max; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
FX_PLUGIN_IDENTIFIER(MagicWandFx, magicWandFx);