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