Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "blend.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//TPoint structure
Toshihiro Shimizu 890ddd
#include "tgeometry.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Palette - pixel functions
Toshihiro Shimizu 890ddd
#include "tpalette.h"
Toshihiro Shimizu 890ddd
#include "tpixelutils.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <vector></vector>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===========================
Toshihiro Shimizu 890ddd
//    Blur pattern class
Toshihiro Shimizu 890ddd
//---------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! The BlurPattern class delineates the idea of a 'blur'
Toshihiro Shimizu 890ddd
//! pattern from a number of random sample points taken
Toshihiro Shimizu 890ddd
//! in a neighbourhood of the blurred pixel. The pattern
Toshihiro Shimizu 890ddd
//! develops in a radial manner if specified, so that possible
Toshihiro Shimizu 890ddd
//! 'obstacles' in the blur can be identified.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class BlurPattern
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	typedef std::vector<tpoint> SamplePath;</tpoint>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<tpoint> m_samples;</tpoint>
Toshihiro Shimizu 890ddd
	std::vector<samplepath> m_samplePaths;</samplepath>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	BlurPattern(double distance, unsigned int samplesCount, bool radial);
Toshihiro Shimizu 890ddd
	~BlurPattern() {}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Builds the specified number of samples count, inside the specified distance
Toshihiro Shimizu 890ddd
//from the origin. If the pattern is radial, paths to the samples points are
Toshihiro Shimizu 890ddd
//calculated.
Toshihiro Shimizu 890ddd
BlurPattern::BlurPattern(double distance, unsigned int samplesCount, bool radial)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const double randFactor = 2.0 * distance / RAND_MAX;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_samples.resize(samplesCount);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build the samples
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < samplesCount; ++i) {
Toshihiro Shimizu 890ddd
		//NOTE: The following method ensures a perfectly flat probability distribution.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TPoint candidatePoint(tround(rand() * randFactor - distance), tround(rand() * randFactor - distance));
Toshihiro Shimizu 890ddd
		double distanceSq = sq(distance);
Toshihiro Shimizu 890ddd
		while (sq(candidatePoint.x) + sq(candidatePoint.y) > distanceSq)
Toshihiro Shimizu 890ddd
			candidatePoint = TPoint(tround(rand() * randFactor - distance), tround(rand() * randFactor - distance));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_samples[i] = candidatePoint;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_samplePaths.resize(samplesCount);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//If necessary, build the paths
Toshihiro Shimizu 890ddd
	if (radial) {
Toshihiro Shimizu 890ddd
		for (i = 0; i < samplesCount; ++i) {
Toshihiro Shimizu 890ddd
			TPoint &sample = m_samples[i];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			int l = tmax(abs(sample.x), abs(sample.y));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_samplePaths[i].reserve(l);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			double dx = sample.x / (double)l;
Toshihiro Shimizu 890ddd
			double dy = sample.y / (double)l;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			double x, y;
Toshihiro Shimizu 890ddd
			int j;
Toshihiro Shimizu 890ddd
			for (j = 0, x = dx, y = dy; j < l; x += dx, y += dy, ++j)
Toshihiro Shimizu 890ddd
				m_samplePaths[i].push_back(TPoint(tround(x), tround(y)));
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=================================
Toshihiro Shimizu 890ddd
//    Raster Selection classes
Toshihiro Shimizu 890ddd
//---------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct SelectionData {
Toshihiro Shimizu 890ddd
	UCHAR m_selectedInk : 1;
Toshihiro Shimizu 890ddd
	UCHAR m_selectedPaint : 1;
Toshihiro Shimizu 890ddd
	UCHAR m_pureInk : 1;
Toshihiro Shimizu 890ddd
	UCHAR m_purePaint : 1;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Implements an array of selection infos using bitfields. It seems that bitfields are more optimized than
Toshihiro Shimizu 890ddd
// using raw bits and bitwise operators, and use just the double of the space required with bit arrays.
Toshihiro Shimizu 890ddd
class SelectionArrayPtr
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	SelectionData *m_buffer;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	SelectionArrayPtr() : m_buffer(0) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline void allocate(unsigned int count)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_buffer = new SelectionData[count];
Toshihiro Shimizu 890ddd
		memset(m_buffer, 0, count * sizeof(SelectionData));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline void destroy()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		delete[] m_buffer;
Toshihiro Shimizu 890ddd
		m_buffer = 0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline SelectionData *data() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return m_buffer;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline SelectionData *data()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return m_buffer;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Bitmap used to store blend color selections and pure color informations.
Toshihiro Shimizu 890ddd
class SelectionRaster
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	SelectionArrayPtr m_selection;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int m_wrap;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	SelectionRaster(TRasterCM32P cm);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void updateSelection(TRasterCM32P cm, const BlendParam ¶m);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	SelectionData *data() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return m_selection.data();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	SelectionData *data()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return m_selection.data();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void destroy()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_selection.destroy();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isSelectedInk(int xy) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return (m_selection.data() + xy)->m_selectedInk;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isSelectedInk(int x, int y) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return isSelectedInk(x + y * m_wrap);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isSelectedPaint(int xy) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return (m_selection.data() + xy)->m_selectedPaint;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isSelectedPaint(int x, int y) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return isSelectedPaint(x + y * m_wrap);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isPureInk(int xy) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return (m_selection.data() + xy)->m_pureInk;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isPureInk(int x, int y) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return isPureInk(x + y * m_wrap);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isPurePaint(int xy) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return (m_selection.data() + xy)->m_purePaint;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isPurePaint(int x, int y) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return isPurePaint(x + y * m_wrap);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isToneColor(int xy) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return !(isPureInk(xy) || isPurePaint(xy));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isToneColor(int x, int y) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return isToneColor(x + y * m_wrap);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline UCHAR linearSearch(const int *v, unsigned int vSize, int k)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const int *vEnd = v + vSize;
Toshihiro Shimizu 890ddd
	for (; v < vEnd; ++v)
Toshihiro Shimizu 890ddd
		if (*v == k)
Toshihiro Shimizu 890ddd
			return 1;
Toshihiro Shimizu 890ddd
	return 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// I've seen the std::binary_search go particularly slow... perhaps it was the debug mode,
Toshihiro Shimizu 890ddd
// but I guess this is the fastest version possible.
Toshihiro Shimizu 890ddd
inline UCHAR binarySearch(const int *v, unsigned int vSize, int k)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//NOTE: v.size() > 0 due to external restrictions. See SelectionRaster's constructor.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int a = -1, b, c = vSize;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (b = c >> 1; b != a; b = (a + c) >> 1) {
Toshihiro Shimizu 890ddd
		if (v[b] == k)
Toshihiro Shimizu 890ddd
			return 1;
Toshihiro Shimizu 890ddd
		else if (k < v[b])
Toshihiro Shimizu 890ddd
			c = b;
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			a = b;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
SelectionRaster::SelectionRaster(TRasterCM32P cm)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	unsigned int lx = cm->getLx(), ly = cm->getLy(), wrap = cm->getWrap();
Toshihiro Shimizu 890ddd
	unsigned int size = lx * ly;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_wrap = lx;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_selection.allocate(size);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	cm->lock();
Toshihiro Shimizu 890ddd
	TPixelCM32 *pix, *pixBegin = (TPixelCM32 *)cm->getRawData();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	SelectionData *selData = data();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int i, j;
Toshihiro Shimizu 890ddd
	for (i = 0; i < ly; ++i) {
Toshihiro Shimizu 890ddd
		pix = pixBegin + i * wrap;
Toshihiro Shimizu 890ddd
		for (j = 0; j < lx; ++j, ++pix, ++selData) {
Toshihiro Shimizu 890ddd
			selData->m_pureInk = pix->getTone() == 0;
Toshihiro Shimizu 890ddd
			selData->m_purePaint = pix->getTone() == 255;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	cm->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void SelectionRaster::updateSelection(TRasterCM32P cm, const BlendParam ¶m)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Make a hard copy of color indexes. We do so since we absolutely prefer
Toshihiro Shimizu 890ddd
	//having them SORTED!
Toshihiro Shimizu 890ddd
	std::vector<int> cIndexes = param.colorsIndexes;</int>
Toshihiro Shimizu 890ddd
	std::sort(cIndexes.begin(), cIndexes.end());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int lx = cm->getLx(), ly = cm->getLy(), wrap = cm->getWrap();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Scan each cm pixel, looking if its ink or paint is in param's colorIndexes.
Toshihiro Shimizu 890ddd
	cm->lock();
Toshihiro Shimizu 890ddd
	TPixelCM32 *pix, *pixBegin = (TPixelCM32 *)cm->getRawData();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	SelectionData *selData = data();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const int *v = &cIndexes[0]; //NOTE: cIndexes.size() > 0 due to external check.
Toshihiro Shimizu 890ddd
	unsigned int vSize = cIndexes.size();
Toshihiro Shimizu 890ddd
	unsigned int i, j;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//NOTE: It seems that linear searches are definitely best for small color indexes.
Toshihiro Shimizu 890ddd
	if (vSize > 50) {
Toshihiro Shimizu 890ddd
		for (i = 0; i < ly; ++i) {
Toshihiro Shimizu 890ddd
			pix = pixBegin + i * wrap;
Toshihiro Shimizu 890ddd
			for (j = 0; j < lx; ++j, ++pix, ++selData) {
Toshihiro Shimizu 890ddd
				selData->m_selectedInk = binarySearch(v, vSize, pix->getInk());
Toshihiro Shimizu 890ddd
				selData->m_selectedPaint = binarySearch(v, vSize, pix->getPaint());
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		for (i = 0; i < ly; ++i) {
Toshihiro Shimizu 890ddd
			pix = pixBegin + i * wrap;
Toshihiro Shimizu 890ddd
			for (j = 0; j < lx; ++j, ++pix, ++selData) {
Toshihiro Shimizu 890ddd
				selData->m_selectedInk = linearSearch(v, vSize, pix->getInk());
Toshihiro Shimizu 890ddd
				selData->m_selectedPaint = linearSearch(v, vSize, pix->getPaint());
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	cm->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================
Toshihiro Shimizu 890ddd
//    Blend functions
Toshihiro Shimizu 890ddd
//------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Pixel whose channels are doubles. Used to store intermediate values for pixel blending.
Toshihiro Shimizu 890ddd
struct DoubleRGBMPixel {
Toshihiro Shimizu 890ddd
	double r;
Toshihiro Shimizu 890ddd
	double g;
Toshihiro Shimizu 890ddd
	double b;
Toshihiro Shimizu 890ddd
	double m;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	DoubleRGBMPixel() : r(0.0), g(0.0), b(0.0), m(0.0) {}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
const double maxTone = TPixelCM32::getMaxTone();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Returns the ink & paint convex factors associated with passed tone.
Toshihiro Shimizu 890ddd
inline void getFactors(int tone, double &inkFactor, double &paintFactor)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	paintFactor = tone / maxTone;
Toshihiro Shimizu 890ddd
	inkFactor = (1.0 - paintFactor);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Copies the cmIn paint and ink colors to the output rasters.
Toshihiro Shimizu 890ddd
void buildLayers(
Toshihiro Shimizu 890ddd
	const TRasterCM32P &cmIn, const std::vector<tpixel32> &palColors,</tpixel32>
Toshihiro Shimizu 890ddd
	TRaster32P &inkRaster, TRaster32P &paintRaster)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Separate cmIn by copying the ink & paint colors directly to the layer rasters.
Toshihiro Shimizu 890ddd
	TPixelCM32 *cmPix, *cmBegin = (TPixelCM32 *)cmIn->getRawData();
Toshihiro Shimizu 890ddd
	TPixel32 *inkPix = (TPixel32 *)inkRaster->getRawData();
Toshihiro Shimizu 890ddd
	TPixel32 *paintPix = (TPixel32 *)paintRaster->getRawData();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int i, j, lx = cmIn->getLx(), ly = cmIn->getLy(), wrap = cmIn->getWrap();
Toshihiro Shimizu 890ddd
	for (i = 0; i < ly; ++i) {
Toshihiro Shimizu 890ddd
		cmPix = cmBegin + i * wrap;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (j = 0; j < lx; ++j, ++cmPix, ++inkPix, ++paintPix) {
Toshihiro Shimizu 890ddd
			*inkPix = palColors[cmPix->getInk()];
Toshihiro Shimizu 890ddd
			*paintPix = palColors[cmPix->getPaint()];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//Should pure colors be checked...?
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Returns true or false whether the selectedColor is the only selectable color
Toshihiro Shimizu 890ddd
// in the neighbourhood. If so, the blend copies it to the output layer pixel directly.
Toshihiro Shimizu 890ddd
inline bool isFlatNeighbourhood(
Toshihiro Shimizu 890ddd
	int selectedColor,
Toshihiro Shimizu 890ddd
	const TRasterCM32P &cmIn, const TPoint &pos,
Toshihiro Shimizu 890ddd
	const SelectionRaster &selRas,
Toshihiro Shimizu 890ddd
	const BlurPattern &blurPattern)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TPixelCM32 &pix = cmIn->pixels(pos.y)[pos.x];
Toshihiro Shimizu 890ddd
	int lx = cmIn->getLx(), ly = cmIn->getLy();
Toshihiro Shimizu 890ddd
	unsigned int xy;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPoint samplePix;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TPoint *samplePoint = blurPattern.m_samples.empty() ? 0 : &blurPattern.m_samples[0];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Read the samples to determine if they only have posSelectedColor
Toshihiro Shimizu 890ddd
	unsigned int i, samplesCount = blurPattern.m_samples.size();
Toshihiro Shimizu 890ddd
	for (i = 0; i < samplesCount; ++i, ++samplePoint) {
Toshihiro Shimizu 890ddd
		//Make sure the sample is inside the image
Toshihiro Shimizu 890ddd
		samplePix.x = pos.x + samplePoint->x;
Toshihiro Shimizu 890ddd
		samplePix.y = pos.y + samplePoint->y;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		xy = samplePix.x + lx * samplePix.y;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (samplePix.x < 0 || samplePix.y < 0 || samplePix.x >= lx || samplePix.y >= ly)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (!selRas.isPurePaint(xy) && selRas.isSelectedInk(xy))
Toshihiro Shimizu 890ddd
			if (cmIn->pixels(samplePix.y)[samplePix.x].getInk() != selectedColor)
Toshihiro Shimizu 890ddd
				return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (!selRas.isPureInk(xy) && selRas.isSelectedPaint(xy))
Toshihiro Shimizu 890ddd
			if (cmIn->pixels(samplePix.y)[samplePix.x].getPaint() != selectedColor)
Toshihiro Shimizu 890ddd
				return false;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Calculates the estimate of blend selection in the neighbourhood specified by
Toshihiro Shimizu 890ddd
// blurPattern.
Toshihiro Shimizu 890ddd
inline void addSamples(
Toshihiro Shimizu 890ddd
	const TRasterCM32P &cmIn, const TPoint &pos,
Toshihiro Shimizu 890ddd
	const TRaster32P &inkRas, const TRaster32P &paintRas,
Toshihiro Shimizu 890ddd
	const SelectionRaster &selRas,
Toshihiro Shimizu 890ddd
	const BlurPattern &blurPattern,
Toshihiro Shimizu 890ddd
	DoubleRGBMPixel &pixSum, double &factorsSum)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	double inkFactor, paintFactor;
Toshihiro Shimizu 890ddd
	unsigned int xy, j, l;
Toshihiro Shimizu 890ddd
	int lx = cmIn->getLx(), ly = cmIn->getLy();
Toshihiro Shimizu 890ddd
	TPixel32 *color;
Toshihiro Shimizu 890ddd
	TPoint samplePos, pathPos;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TPoint *samplePoint = blurPattern.m_samples.empty() ? 0 : &blurPattern.m_samples[0];
Toshihiro Shimizu 890ddd
	const TPoint *pathPoint;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int i, blurSamplesCount = blurPattern.m_samples.size();
Toshihiro Shimizu 890ddd
	for (i = 0; i < blurSamplesCount; ++i, ++samplePoint) {
Toshihiro Shimizu 890ddd
		//Add each samples contribute to the sum
Toshihiro Shimizu 890ddd
		samplePos.x = pos.x + samplePoint->x;
Toshihiro Shimizu 890ddd
		samplePos.y = pos.y + samplePoint->y;
Toshihiro Shimizu 890ddd
		if (samplePos.x < 0 || samplePos.y < 0 || samplePos.x >= lx || samplePos.y >= ly)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Ensure that each pixel on the sample's path (if any) is selected
Toshihiro Shimizu 890ddd
		l = blurPattern.m_samplePaths[i].size();
Toshihiro Shimizu 890ddd
		pathPoint = blurPattern.m_samplePaths[i].empty() ? 0 : &blurPattern.m_samplePaths[i][0];
Toshihiro Shimizu 890ddd
		for (j = 0; j < l; ++j, ++pathPoint) {
Toshihiro Shimizu 890ddd
			pathPos.x = pos.x + pathPoint->x;
Toshihiro Shimizu 890ddd
			pathPos.y = pos.y + pathPoint->y;
Toshihiro Shimizu 890ddd
			xy = pathPos.x + lx * pathPos.y;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (!(selRas.isPurePaint(xy) || selRas.isSelectedInk(xy)))
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (!(selRas.isPureInk(xy) || selRas.isSelectedPaint(xy)))
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (j < l)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		xy = samplePos.x + lx * samplePos.y;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (selRas.isSelectedInk(xy) && !selRas.isPurePaint(xy)) {
Toshihiro Shimizu 890ddd
			getFactors(cmIn->pixels(samplePos.y)[samplePos.x].getTone(), inkFactor, paintFactor);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			color = &inkRas->pixels(samplePos.y)[samplePos.x];
Toshihiro Shimizu 890ddd
			pixSum.r += inkFactor * color->r;
Toshihiro Shimizu 890ddd
			pixSum.g += inkFactor * color->g;
Toshihiro Shimizu 890ddd
			pixSum.b += inkFactor * color->b;
Toshihiro Shimizu 890ddd
			pixSum.m += inkFactor * color->m;
Toshihiro Shimizu 890ddd
			factorsSum += inkFactor;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (selRas.isSelectedPaint(xy) && !selRas.isPureInk(xy)) {
Toshihiro Shimizu 890ddd
			getFactors(cmIn->pixels(samplePos.y)[samplePos.x].getTone(), inkFactor, paintFactor);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			color = &paintRas->pixels(samplePos.y)[samplePos.x];
Toshihiro Shimizu 890ddd
			pixSum.r += paintFactor * color->r;
Toshihiro Shimizu 890ddd
			pixSum.g += paintFactor * color->g;
Toshihiro Shimizu 890ddd
			pixSum.b += paintFactor * color->b;
Toshihiro Shimizu 890ddd
			pixSum.m += paintFactor * color->m;
Toshihiro Shimizu 890ddd
			factorsSum += paintFactor;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef std::pair<traster32p, traster32p=""> RGBMRasterPair;</traster32p,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Performs a single color blending. This function can be repeatedly invoked to
Toshihiro Shimizu 890ddd
// perform multiple color blending.
Toshihiro Shimizu 890ddd
inline void doBlend(
Toshihiro Shimizu 890ddd
	const TRasterCM32P &cmIn,
Toshihiro Shimizu 890ddd
	RGBMRasterPair &inkLayer, RGBMRasterPair &paintLayer,
Toshihiro Shimizu 890ddd
	const SelectionRaster &selRas,
Toshihiro Shimizu 890ddd
	const std::vector<blurpattern> &blurPatterns)</blurpattern>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Declare some vars
Toshihiro Shimizu 890ddd
	unsigned int blurPatternsCount = blurPatterns.size();
Toshihiro Shimizu 890ddd
	int lx = cmIn->getLx(), ly = cmIn->getLy();
Toshihiro Shimizu 890ddd
	double totalFactor;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPixelCM32 *cmPix, *cmBegin = (TPixelCM32 *)cmIn->getRawData();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPixel32
Toshihiro Shimizu 890ddd
		*inkIn = (TPixel32 *)inkLayer.first->getRawData(),
Toshihiro Shimizu 890ddd
		*inkOut = (TPixel32 *)inkLayer.second->getRawData(),
Toshihiro Shimizu 890ddd
		*paintIn = (TPixel32 *)paintLayer.first->getRawData(),
Toshihiro Shimizu 890ddd
		*paintOut = (TPixel32 *)paintLayer.second->getRawData();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const BlurPattern *blurPattern, *blurPatternsBegin = &blurPatterns[0];
Toshihiro Shimizu 890ddd
	bool builtSamples = false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	DoubleRGBMPixel samplesSum;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//For every cmIn pixel
Toshihiro Shimizu 890ddd
	TPoint pos;
Toshihiro Shimizu 890ddd
	SelectionData *selData = selRas.data();
Toshihiro Shimizu 890ddd
	cmPix = cmBegin;
Toshihiro Shimizu 890ddd
	for (pos.y = 0; pos.y < ly; ++pos.y, cmPix = cmBegin + pos.y * cmIn->getWrap())
Toshihiro Shimizu 890ddd
		for (pos.x = 0; pos.x < lx; ++pos.x, ++inkIn, ++inkOut, ++paintIn, ++paintOut, ++selData, ++cmPix) {
Toshihiro Shimizu 890ddd
			blurPattern = blurPatternsBegin + (rand() % blurPatternsCount);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//Build the ink blend color
Toshihiro Shimizu 890ddd
			if (!selData->m_purePaint && selData->m_selectedInk) {
Toshihiro Shimizu 890ddd
				if (!builtSamples) {
Toshihiro Shimizu 890ddd
					//Build samples contributes
Toshihiro Shimizu 890ddd
					totalFactor = 1.0;
Toshihiro Shimizu 890ddd
					samplesSum.r = samplesSum.g = samplesSum.b = samplesSum.m = 0.0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					if (!isFlatNeighbourhood(cmPix->getInk(), cmIn, pos, selRas, *blurPattern))
Toshihiro Shimizu 890ddd
						addSamples(cmIn, pos, inkLayer.first, paintLayer.first, selRas, *blurPattern,
Toshihiro Shimizu 890ddd
								   samplesSum, totalFactor);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					builtSamples = true;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				//Output the blended pixel
Toshihiro Shimizu 890ddd
				inkOut->r = (samplesSum.r + inkIn->r) / totalFactor;
Toshihiro Shimizu 890ddd
				inkOut->g = (samplesSum.g + inkIn->g) / totalFactor;
Toshihiro Shimizu 890ddd
				inkOut->b = (samplesSum.b + inkIn->b) / totalFactor;
Toshihiro Shimizu 890ddd
				inkOut->m = (samplesSum.m + inkIn->m) / totalFactor;
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				//If the color is not blended, then just copy the old layer pixel
Toshihiro Shimizu 890ddd
				*inkOut = *inkIn;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//Build the paint blend color
Toshihiro Shimizu 890ddd
			if (!selData->m_pureInk && selData->m_selectedPaint) {
Toshihiro Shimizu 890ddd
				if (!builtSamples) {
Toshihiro Shimizu 890ddd
					//Build samples contributes
Toshihiro Shimizu 890ddd
					totalFactor = 1.0;
Toshihiro Shimizu 890ddd
					samplesSum.r = samplesSum.g = samplesSum.b = samplesSum.m = 0.0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					if (!isFlatNeighbourhood(cmPix->getPaint(), cmIn, pos, selRas, *blurPattern))
Toshihiro Shimizu 890ddd
						addSamples(cmIn, pos, inkLayer.first, paintLayer.first, selRas, *blurPattern,
Toshihiro Shimizu 890ddd
								   samplesSum, totalFactor);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					builtSamples = true;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				//Output the blended pixel
Toshihiro Shimizu 890ddd
				paintOut->r = (samplesSum.r + paintIn->r) / totalFactor;
Toshihiro Shimizu 890ddd
				paintOut->g = (samplesSum.g + paintIn->g) / totalFactor;
Toshihiro Shimizu 890ddd
				paintOut->b = (samplesSum.b + paintIn->b) / totalFactor;
Toshihiro Shimizu 890ddd
				paintOut->m = (samplesSum.m + paintIn->m) / totalFactor;
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				//If the color is not blended, then just copy the old layer pixel
Toshihiro Shimizu 890ddd
				*paintOut = *paintIn;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			builtSamples = false;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef std::vector<blurpattern> BlurPatternContainer;</blurpattern>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! This function performs a group of  spatial color blending <\a> operations on Toonz Images.
Toshihiro Shimizu 890ddd
    The BlendParam structure stores the blend options recognized by this function; it includes
Toshihiro Shimizu 890ddd
    a list of the palette indexes involved in the blend operation, plus:
Toshihiro Shimizu 890ddd
    \li \b Intensity represents the \a radius of the blur operation between blend colors.
Toshihiro Shimizu 890ddd
    \li \b Smoothness is the number of samples per pixel used to approximate the blur.
Toshihiro Shimizu 890ddd
    
  • Stop at Contour <\b> specifies if lines from pixels to neighbouring samples
  • Toshihiro Shimizu 890ddd
             should not trespass color indexes not included in the blend operation <\li>
    Toshihiro Shimizu 890ddd
        The succession of input blend parameters are applied in the order.
    Toshihiro Shimizu 890ddd
    */
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    template <typename pixel=""></typename>
    Toshihiro Shimizu 890ddd
    void blend(TToonzImageP ti, TRasterPT<pixel> rasOut, const std::vector<blendparam> ¶ms)</blendparam></pixel>
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    	assert(ti->getRaster()->getSize() == rasOut->getSize());
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	//Extract the interesting raster. It should be the savebox of passed cmap, plus - if
    Toshihiro Shimizu 890ddd
    	//some param has the 0 index as blending color - the intensity of that blend param.
    Toshihiro Shimizu 890ddd
    	unsigned int i, j;
    Toshihiro Shimizu 890ddd
    	TRect saveBox(ti->getSavebox());
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	int enlargement = 0;
    Toshihiro Shimizu 890ddd
    	for (i = 0; i < params.size(); ++i)
    Toshihiro Shimizu 890ddd
    		for (j = 0; j < params[i].colorsIndexes.size(); ++j)
    Toshihiro Shimizu 890ddd
    			if (params[i].colorsIndexes[j] == 0)
    Toshihiro Shimizu 890ddd
    				enlargement = tmax(enlargement, tceil(params[i].intensity));
    Toshihiro Shimizu 890ddd
    	saveBox = saveBox.enlarge(enlargement);
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	TRasterCM32P cmIn(ti->getRaster()->extract(saveBox));
    Toshihiro Shimizu 890ddd
    	TRasterPT<pixel> rasOutExtract = rasOut->extract(saveBox);</pixel>
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	//Ensure that cmIn and rasOut have the same size
    Toshihiro Shimizu 890ddd
    	unsigned int lx = cmIn->getLx(), ly = cmIn->getLy();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	//Build the pure colors infos
    Toshihiro Shimizu 890ddd
    	SelectionRaster selectionRaster(cmIn);
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	//Now, build a little group of BlurPatterns - and for each, one for passed param.
    Toshihiro Shimizu 890ddd
    	//A small number of patterns per param is needed to make the pattern look not ever the same.
    Toshihiro Shimizu 890ddd
    	const int blurPatternsPerParam = 10;
    Toshihiro Shimizu 890ddd
    	std::vector<blurpatterncontainer> blurGroup(params.size());</blurpatterncontainer>
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	for (i = 0; i < params.size(); ++i) {
    Toshihiro Shimizu 890ddd
    		BlurPatternContainer &blurContainer = blurGroup[i];
    Toshihiro Shimizu 890ddd
    		blurContainer.reserve(blurPatternsPerParam);
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		for (j = 0; j < blurPatternsPerParam; ++j)
    Toshihiro Shimizu 890ddd
    			blurContainer.push_back(BlurPattern(params[i].intensity, params[i].smoothness, params[i].stopAtCountour));
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	//Build the palette
    Toshihiro Shimizu 890ddd
    	TPalette *palette = ti->getPalette();
    Toshihiro Shimizu 890ddd
    	std::vector<tpixel32> paletteColors;</tpixel32>
    Toshihiro Shimizu 890ddd
    	paletteColors.resize(palette->getStyleCount());
    Toshihiro Shimizu 890ddd
    	for (i = 0; i < paletteColors.size(); ++i)
    Toshihiro Shimizu 890ddd
    		paletteColors[i] = premultiply(palette->getStyle(i)->getAverageColor());
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	//Build the 4 auxiliary rasters for the blending procedure: they are ink / paint versus input / output in the blend.
    Toshihiro Shimizu 890ddd
    	//The output raster is reused to spare some memory - it should be, say, the inkLayer's second at the end of the overall
    Toshihiro Shimizu 890ddd
    	//blending procedure. It could be the first, without the necessity of clearing it before blending the layers, but things
    Toshihiro Shimizu 890ddd
    	//get more complicated when PIXEL is TPixel64...
    Toshihiro Shimizu 890ddd
    	RGBMRasterPair inkLayer, paintLayer;
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	TRaster32P rasOut32P_1(lx, ly, lx, (TPixel32 *)rasOut->getRawData(), false);
    Toshihiro Shimizu 890ddd
    	inkLayer.first = (params.size() % 2) ? rasOut32P_1 : TRaster32P(lx, ly);
    Toshihiro Shimizu 890ddd
    	inkLayer.second = (params.size() % 2) ? TRaster32P(lx, ly) : rasOut32P_1;
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	if (PIXEL::maxChannelValue >= TPixel64::maxChannelValue) {
    Toshihiro Shimizu 890ddd
    		TRaster32P rasOut32P_2(lx, ly, lx, ((TPixel32 *)rasOut->getRawData()) + lx * ly, false);
    Toshihiro Shimizu 890ddd
    		paintLayer.first = (params.size() % 2) ? rasOut32P_2 : TRaster32P(lx, ly);
    Toshihiro Shimizu 890ddd
    		paintLayer.second = (params.size() % 2) ? TRaster32P(lx, ly) : rasOut32P_2;
    Toshihiro Shimizu 890ddd
    	} else {
    Toshihiro Shimizu 890ddd
    		paintLayer.first = TRaster32P(lx, ly);
    Toshihiro Shimizu 890ddd
    		paintLayer.second = TRaster32P(lx, ly);
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	inkLayer.first->clear();
    Toshihiro Shimizu 890ddd
    	inkLayer.second->clear();
    Toshihiro Shimizu 890ddd
    	paintLayer.first->clear();
    Toshihiro Shimizu 890ddd
    	paintLayer.second->clear();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	//Now, we have to perform the blur of each of the cm's pixels.
    Toshihiro Shimizu 890ddd
    	cmIn->lock();
    Toshihiro Shimizu 890ddd
    	rasOut->lock();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	inkLayer.first->lock();
    Toshihiro Shimizu 890ddd
    	inkLayer.second->lock();
    Toshihiro Shimizu 890ddd
    	paintLayer.first->lock();
    Toshihiro Shimizu 890ddd
    	paintLayer.second->lock();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	//Convert the initial cmIn to fullcolor ink - paint layers
    Toshihiro Shimizu 890ddd
    	buildLayers(cmIn, paletteColors, inkLayer.first, paintLayer.first);
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	//Perform the blend on separated ink - paint layers
    Toshihiro Shimizu 890ddd
    	for (i = 0; i < params.size(); ++i) {
    Toshihiro Shimizu 890ddd
    		if (params[i].colorsIndexes.size() == 0)
    Toshihiro Shimizu 890ddd
    			continue;
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		selectionRaster.updateSelection(cmIn, params[i]);
    Toshihiro Shimizu 890ddd
    		doBlend(cmIn, inkLayer, paintLayer, selectionRaster, blurGroup[i]);
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		tswap(inkLayer.first, inkLayer.second);
    Toshihiro Shimizu 890ddd
    		tswap(paintLayer.first, paintLayer.second);
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	//Release the unnecessary rasters
    Toshihiro Shimizu 890ddd
    	inkLayer.second->unlock();
    Toshihiro Shimizu 890ddd
    	paintLayer.second->unlock();
    Toshihiro Shimizu 890ddd
    	inkLayer.second = TRaster32P();
    Toshihiro Shimizu 890ddd
    	paintLayer.second = TRaster32P();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	//Clear rasOut - since it was reused to spare space...
    Toshihiro Shimizu 890ddd
    	rasOut->clear();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	//Add the ink & paint layers on the output raster
    Toshihiro Shimizu 890ddd
    	double PIXELmaxChannelValue = PIXEL::maxChannelValue;
    Toshihiro Shimizu 890ddd
    	double toPIXELFactor = PIXELmaxChannelValue / (double)TPixel32::maxChannelValue;
    Toshihiro Shimizu 890ddd
    	double inkFactor, paintFactor;
    Toshihiro Shimizu 890ddd
    	TPoint pos;
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	PIXEL *outPix, *outBegin = (PIXEL *)rasOutExtract->getRawData();
    Toshihiro Shimizu 890ddd
    	TPixelCM32 *cmPix, *cmBegin = (TPixelCM32 *)cmIn->getRawData();
    Toshihiro Shimizu 890ddd
    	int wrap = rasOutExtract->getWrap();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	TPixel32 *inkPix = (TPixel32 *)inkLayer.first->getRawData();
    Toshihiro Shimizu 890ddd
    	TPixel32 *paintPix = (TPixel32 *)paintLayer.first->getRawData();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	for (i = 0; i < ly; ++i) {
    Toshihiro Shimizu 890ddd
    		outPix = outBegin + wrap * i;
    Toshihiro Shimizu 890ddd
    		cmPix = cmBegin + wrap * i;
    Toshihiro Shimizu 890ddd
    		for (j = 0; j < lx; ++j, ++outPix, ++cmPix, ++inkPix, ++paintPix) {
    Toshihiro Shimizu 890ddd
    			getFactors(cmPix->getTone(), inkFactor, paintFactor);
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    			outPix->r = tcrop(toPIXELFactor * (inkFactor * inkPix->r + paintFactor * paintPix->r), 0.0, PIXELmaxChannelValue);
    Toshihiro Shimizu 890ddd
    			outPix->g = tcrop(toPIXELFactor * (inkFactor * inkPix->g + paintFactor * paintPix->g), 0.0, PIXELmaxChannelValue);
    Toshihiro Shimizu 890ddd
    			outPix->b = tcrop(toPIXELFactor * (inkFactor * inkPix->b + paintFactor * paintPix->b), 0.0, PIXELmaxChannelValue);
    Toshihiro Shimizu 890ddd
    			outPix->m = tcrop(toPIXELFactor * (inkFactor * inkPix->m + paintFactor * paintPix->m), 0.0, PIXELmaxChannelValue);
    Toshihiro Shimizu 890ddd
    		}
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	inkLayer.first->unlock();
    Toshihiro Shimizu 890ddd
    	paintLayer.first->unlock();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	cmIn->unlock();
    Toshihiro Shimizu 890ddd
    	rasOut->unlock();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	//Destroy the auxiliary bitmaps
    Toshihiro Shimizu 890ddd
    	selectionRaster.destroy();
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    template void blend<tpixel32>(TToonzImageP cmIn, TRasterPT<tpixel32> rasOut, const std::vector<blendparam> ¶ms);</blendparam></tpixel32></tpixel32>
    Toshihiro Shimizu 890ddd
    template void blend<tpixel64>(TToonzImageP cmIn, TRasterPT<tpixel64> rasOut, const std::vector<blendparam> ¶ms);</blendparam></tpixel64></tpixel64>