|
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>
|