|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "stdfx.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tfxparam.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tpixelutils.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "trop.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tparamset.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//****************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
// Local namespace stuff
|
|
Toshihiro Shimizu |
890ddd |
//****************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
namespace {
|
|
Toshihiro Shimizu |
890ddd |
inline void pixelConvert(TPixel32 &dst, const TPixel32 &src) { dst = src; }
|
|
Shinya Kitaoka |
120a6e |
inline void pixelConvert(TPixel64 &dst, const TPixel32 &src) {
|
|
Shinya Kitaoka |
120a6e |
dst = toPixel64(src);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
inline TRect gridAlign(const TRect &rect, TPoint origin, double step) {
|
|
Shinya Kitaoka |
120a6e |
TRect result(rect);
|
|
Shinya Kitaoka |
120a6e |
result -= origin;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
result.x0 = step * tfloor(result.x0 / step);
|
|
Shinya Kitaoka |
120a6e |
result.y0 = step * tfloor(result.y0 / step);
|
|
Shinya Kitaoka |
120a6e |
result.x1 = step * tceil((result.x1 + 1) / step) - 1;
|
|
Shinya Kitaoka |
120a6e |
result.y1 = step * tceil((result.y1 + 1) / step) - 1;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
result += origin;
|
|
Shinya Kitaoka |
120a6e |
return result;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
inline TRectD gridAlign(const TRectD &rect, TPointD origin, double step) {
|
|
Shinya Kitaoka |
120a6e |
TRectD result(rect);
|
|
Shinya Kitaoka |
120a6e |
result -= origin;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
result.x0 = step * tfloor(result.x0 / step);
|
|
Shinya Kitaoka |
120a6e |
result.y0 = step * tfloor(result.y0 / step);
|
|
Shinya Kitaoka |
120a6e |
result.x1 = step * tceil(result.x1 / step);
|
|
Shinya Kitaoka |
120a6e |
result.y1 = step * tceil(result.y1 / step);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
result += origin;
|
|
Shinya Kitaoka |
120a6e |
return result;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//****************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
// Mosaic Namespace
|
|
Toshihiro Shimizu |
890ddd |
//****************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
namespace mosaic {
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
The mosaic::CellBuilder class is the virtual base class used by MosaicFx
|
|
Toshihiro Shimizu |
890ddd |
to render a Mosaic cell with supplied colors.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
template <typename pixel=""></typename>
|
|
Shinya Kitaoka |
120a6e |
class CellBuilder {
|
|
Toshihiro Shimizu |
890ddd |
protected:
|
|
Shinya Kitaoka |
120a6e |
int m_lx, m_ly;
|
|
Shinya Kitaoka |
120a6e |
double m_radius;
|
|
Shinya Kitaoka |
120a6e |
int m_wrap;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
CellBuilder(int cellLx, int cellLy, double radius, int wrap)
|
|
Shinya Kitaoka |
120a6e |
: m_lx(cellLx), m_ly(cellLy), m_radius(radius), m_wrap(wrap) {}
|
|
Shinya Kitaoka |
120a6e |
virtual ~CellBuilder() {}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
virtual void doCell(PIXEL *cellBuffer, const PIXEL &cellColor,
|
|
Shinya Kitaoka |
120a6e |
const PIXEL &bgColor, int x0, int y0, int x1, int y1) = 0;
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
} // namespace mosaic
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//****************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
// CellBuilder implementations
|
|
Toshihiro Shimizu |
890ddd |
//****************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
namespace mosaic {
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
template <typename gray="" pixel,="" typename=""></typename>
|
|
Shinya Kitaoka |
120a6e |
class MaskCellBuilder : public CellBuilder<pixel> {</pixel>
|
|
Toshihiro Shimizu |
890ddd |
protected:
|
|
Shinya Kitaoka |
120a6e |
TRasterPT<gray> m_mask;</gray>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
MaskCellBuilder(int cellLx, int cellLy, double radius, int wrap)
|
|
Shinya Kitaoka |
120a6e |
: CellBuilder<pixel>(cellLx, cellLy, radius, wrap) {}</pixel>
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
void doCell(PIXEL *cellBuffer, const PIXEL &cellColor, const PIXEL &bgColor,
|
|
Shinya Kitaoka |
473e70 |
int x0, int y0, int x1, int y1) override {
|
|
Shinya Kitaoka |
120a6e |
// Apply the mask to the cell. 0 pixels are bgColored, GRAY::maxChannelValue
|
|
Shinya Kitaoka |
120a6e |
// ones are cellColored.
|
|
Shinya Kitaoka |
120a6e |
PIXEL *pix, *line = cellBuffer, *lineEnd;
|
|
Shinya Kitaoka |
120a6e |
GRAY *grPix, *grLine = m_mask->pixels(y0) + x0, *grLineEnd;
|
|
Shinya Kitaoka |
120a6e |
int x, y, grWrap = m_mask->getWrap(), lx = x1 - x0;
|
|
Shinya Kitaoka |
120a6e |
for (y = y0; y < y1; ++y, line += this->m_wrap, grLine += grWrap) {
|
|
Shinya Kitaoka |
120a6e |
lineEnd = line + lx;
|
|
Shinya Kitaoka |
120a6e |
grLineEnd = grLine + lx;
|
|
Shinya Kitaoka |
120a6e |
for (x = x0, pix = line, grPix = grLine; x < x1; ++x, ++pix, ++grPix)
|
|
Shinya Kitaoka |
120a6e |
*pix = blend(bgColor, cellColor,
|
|
Shinya Kitaoka |
120a6e |
grPix->value / (double)GRAY::maxChannelValue);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
template <typename gray="" pixel,="" typename=""></typename>
|
|
Shinya Kitaoka |
d1f6c4 |
class SquareBuilder final : public MaskCellBuilder<pixel, gray=""> {</pixel,>
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
SquareBuilder(int cellLx, int cellLy, double radius, int wrap)
|
|
Shinya Kitaoka |
120a6e |
: MaskCellBuilder<pixel, gray="">(cellLx, cellLy, radius, wrap) {</pixel,>
|
|
Shinya Kitaoka |
120a6e |
// Build the mask corresponding to a square of passed radius
|
|
Shinya Kitaoka |
120a6e |
GRAY *pix, *pixRev, *line, *lineEnd, *lineRev;
|
|
Shinya Kitaoka |
120a6e |
this->m_mask = TRasterPT<gray>(cellLx, cellLy);</gray>
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// For each pixel in the lower-left quadrant, fill in the corresponding mask
|
|
Shinya Kitaoka |
120a6e |
// value.
|
|
Shinya Kitaoka |
120a6e |
// The other ones are filled by mirroring.
|
|
Shinya Kitaoka |
120a6e |
int i, j;
|
|
Shinya Kitaoka |
120a6e |
double lxHalf = 0.5 * cellLx, lyHalf = 0.5 * cellLy;
|
|
Shinya Kitaoka |
120a6e |
int lxHalfI = tceil(lxHalf), lyHalfI = tceil(lyHalf);
|
|
Shinya Kitaoka |
120a6e |
double val, addValX = radius - lxHalf + 1, addValY = radius - lyHalf + 1;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < lyHalfI; ++i) {
|
|
Shinya Kitaoka |
120a6e |
line = this->m_mask->pixels(i),
|
|
Shinya Kitaoka |
120a6e |
lineRev = this->m_mask->pixels(cellLy - i - 1);
|
|
Shinya Kitaoka |
120a6e |
lineEnd = line + cellLx;
|
|
Shinya Kitaoka |
120a6e |
for (j = 0, pix = line, pixRev = lineEnd - 1; j < lxHalfI;
|
|
Shinya Kitaoka |
120a6e |
++j, ++pix, --pixRev) {
|
|
Shinya Kitaoka |
120a6e |
val = tcrop(addValX + i, 0.0, 1.0) * tcrop(addValY + j, 0.0, 1.0);
|
|
Shinya Kitaoka |
120a6e |
*pix = *pixRev = val * GRAY::maxChannelValue;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
memcpy(lineRev, line, cellLx * sizeof(GRAY));
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
template <typename gray="" pixel,="" typename=""></typename>
|
|
Shinya Kitaoka |
d1f6c4 |
class CircleBuilder final : public MaskCellBuilder<pixel, gray=""> {</pixel,>
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
CircleBuilder(int cellLx, int cellLy, double radius, int wrap)
|
|
Shinya Kitaoka |
120a6e |
: MaskCellBuilder<pixel, gray="">(cellLx, cellLy, radius, wrap) {</pixel,>
|
|
Shinya Kitaoka |
120a6e |
// Build the mask corresponding to a square of passed radius
|
|
Shinya Kitaoka |
120a6e |
GRAY *pix, *pixRev, *line, *lineEnd, *lineRev;
|
|
Shinya Kitaoka |
120a6e |
this->m_mask = TRasterPT<gray>(cellLx, cellLy);</gray>
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// For each pixel in the lower-left quadrant, fill in the corresponding mask
|
|
Shinya Kitaoka |
120a6e |
// value.
|
|
Shinya Kitaoka |
120a6e |
// The other ones are filled by mirroring.
|
|
Shinya Kitaoka |
120a6e |
int i, j;
|
|
Shinya Kitaoka |
120a6e |
double lxHalf = 0.5 * cellLx, lyHalf = 0.5 * cellLy;
|
|
Shinya Kitaoka |
120a6e |
int lxHalfI = tceil(lxHalf), lyHalfI = tceil(lyHalf);
|
|
Shinya Kitaoka |
120a6e |
double val, addValX = 0.5 - lxHalf, addValY = 0.5 - lyHalf;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < lyHalfI; ++i) {
|
|
Shinya Kitaoka |
120a6e |
line = this->m_mask->pixels(i),
|
|
Shinya Kitaoka |
120a6e |
lineRev = this->m_mask->pixels(cellLy - i - 1);
|
|
Shinya Kitaoka |
120a6e |
lineEnd = line + cellLx;
|
|
Shinya Kitaoka |
120a6e |
for (j = 0, pix = line, pixRev = lineEnd - 1; j < lxHalfI;
|
|
Shinya Kitaoka |
120a6e |
++j, ++pix, --pixRev) {
|
|
Shinya Kitaoka |
120a6e |
val = tcrop(radius - sqrt(sq(i + addValX) + sq(j + addValY)), 0.0, 1.0);
|
|
Shinya Kitaoka |
120a6e |
*pix = *pixRev = val * GRAY::maxChannelValue;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
memcpy(lineRev, line, cellLx * sizeof(GRAY));
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
} // namespace mosaic
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//****************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
// Mosaic Fx
|
|
Toshihiro Shimizu |
890ddd |
//****************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
d1f6c4 |
class MosaicFx final : public TStandardRasterFx {
|
|
Shinya Kitaoka |
120a6e |
FX_PLUGIN_DECLARATION(MosaicFx)
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TRasterFxPort m_input;
|
|
Shinya Kitaoka |
120a6e |
TDoubleParamP m_size;
|
|
Shinya Kitaoka |
120a6e |
TDoubleParamP m_distance;
|
|
Shinya Kitaoka |
120a6e |
TPixelParamP m_bgcolor;
|
|
Shinya Kitaoka |
120a6e |
TIntEnumParamP m_shape;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
MosaicFx()
|
|
Shinya Kitaoka |
120a6e |
: m_size(10.0)
|
|
Shinya Kitaoka |
120a6e |
, m_distance(10.0)
|
|
Shinya Kitaoka |
120a6e |
, m_bgcolor(TPixel32::Transparent)
|
|
Shinya Kitaoka |
120a6e |
, m_shape(new TIntEnumParam(0, "Square")) {
|
|
Shinya Kitaoka |
120a6e |
m_size->setMeasureName("fxLength");
|
|
Shinya Kitaoka |
120a6e |
m_distance->setMeasureName("fxLength");
|
|
Shinya Kitaoka |
120a6e |
bindParam(this, "size", m_size);
|
|
Shinya Kitaoka |
120a6e |
bindParam(this, "distance", m_distance);
|
|
Shinya Kitaoka |
120a6e |
bindParam(this, "bg_color", m_bgcolor);
|
|
Shinya Kitaoka |
120a6e |
bindParam(this, "shape", m_shape);
|
|
Shinya Kitaoka |
120a6e |
addInputPort("Source", m_input);
|
|
Shinya Kitaoka |
120a6e |
m_size->setValueRange(0.0, (std::numeric_limits<double>::max)());</double>
|
|
Shinya Kitaoka |
120a6e |
m_distance->setValueRange(0.0, (std::numeric_limits<double>::max)());</double>
|
|
Shinya Kitaoka |
120a6e |
m_shape->addItem(1, "Round");
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
~MosaicFx(){};
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
38fd86 |
bool doGetBBox(double frame, TRectD &bBox,
|
|
Shinya Kitaoka |
38fd86 |
const TRenderSettings &info) override;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
38fd86 |
void doDryCompute(TRectD &rect, double frame,
|
|
Shinya Kitaoka |
38fd86 |
const TRenderSettings &ri) override;
|
|
Shinya Kitaoka |
473e70 |
void doCompute(TTile &tile, double frame, const TRenderSettings &ri) override;
|
|
Shinya Kitaoka |
120a6e |
int getMemoryRequirement(const TRectD &rect, double frame,
|
|
Shinya Kitaoka |
473e70 |
const TRenderSettings &info) override;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
473e70 |
bool canHandle(const TRenderSettings &info, double frame) override {
|
|
Shinya Kitaoka |
120a6e |
// We'll return the handled affine only through handledAffine().
|
|
Shinya Kitaoka |
120a6e |
if ((m_size->getValue(frame) + m_distance->getValue(frame)) == 0.0)
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Shinya Kitaoka |
120a6e |
return false;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
473e70 |
TAffine handledAffine(const TRenderSettings &info, double frame) override {
|
|
Shinya Kitaoka |
120a6e |
// Return the default implementation: only the scale part of the affine
|
|
Shinya Kitaoka |
120a6e |
// can be handled. Rotations and other distortions would need us have to
|
|
Shinya Kitaoka |
120a6e |
// implement diagonal grid lines - and we don't want to!
|
|
Shinya Kitaoka |
120a6e |
// Also, no translational component will be dealt for the same reason.
|
|
Shinya Kitaoka |
120a6e |
TAffine scalePart(TRasterFx::handledAffine(info, frame));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Plus, we want to avoid dealing with antialiases even on plain orthogonal
|
|
Shinya Kitaoka |
120a6e |
// lines! So, we ensure that the step size will be flattened to integer.
|
|
Shinya Kitaoka |
120a6e |
double stepSize = m_size->getValue(frame) + m_distance->getValue(frame);
|
|
Shinya Kitaoka |
120a6e |
double scale = tceil(stepSize * scalePart.a11) / stepSize;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
return TScale(scale, scale);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
template <typename pixel=""></typename>
|
|
Shinya Kitaoka |
120a6e |
void doMosaic(TRasterPT<pixel> ras, TRasterPT<pixel> cellsRas, int step,</pixel></pixel>
|
|
Shinya Kitaoka |
120a6e |
const TPoint &pos, TPixel32 bgcolor,
|
|
Shinya Kitaoka |
120a6e |
mosaic::CellBuilder<pixel> &cellBuilder) {</pixel>
|
|
Shinya Kitaoka |
120a6e |
// Perform the mosaic's flattening operation on each grid cell.
|
|
Shinya Kitaoka |
120a6e |
// Cells are identified directly as we traverse the raster.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
int lx = ras->getLx(), ly = ras->getLy();
|
|
Shinya Kitaoka |
120a6e |
int wrap = ras->getWrap();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
int cellLx = cellsRas->getLx(), cellLy = cellsRas->getLy(),
|
|
Shinya Kitaoka |
120a6e |
cellWrap = cellsRas->getWrap();
|
|
Shinya Kitaoka |
120a6e |
int cellX, cellY;
|
|
Shinya Kitaoka |
120a6e |
int x0, y0, x1, y1;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
PIXEL actualBgColor;
|
|
Shinya Kitaoka |
120a6e |
pixelConvert(actualBgColor, bgcolor);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
ras->lock();
|
|
Shinya Kitaoka |
120a6e |
cellsRas->lock();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
PIXEL *buffer = ras->pixels(0);
|
|
Shinya Kitaoka |
120a6e |
PIXEL *cellsBuf = cellsRas->pixels(0);
|
|
Shinya Kitaoka |
120a6e |
for (cellY = 0; cellY < cellLy; ++cellY)
|
|
Shinya Kitaoka |
120a6e |
for (cellX = 0; cellX < cellLx; ++cellX) {
|
|
Shinya Kitaoka |
120a6e |
// Build the cell geometry
|
|
Shinya Kitaoka |
120a6e |
x0 = pos.x + cellX * step, y0 = pos.y + cellY * step;
|
|
Shinya Kitaoka |
120a6e |
x1 = x0 + step, y1 = y0 + step;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Retrieve the cell buffer position and its eventual adjustment
|
|
Shinya Kitaoka |
120a6e |
int u0 = std::max(x0, 0), v0 = std::max(y0, 0);
|
|
Shinya Kitaoka |
120a6e |
int u1 = std::min(x1, lx), v1 = std::min(y1, ly);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
PIXEL *cb = buffer + u0 + v0 * wrap;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
u0 -= x0, v0 -= y0, u1 -= x0, v1 -= y0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Retrieve the cell color
|
|
Shinya Kitaoka |
120a6e |
PIXEL *color = cellsBuf + cellX + cellY * cellWrap;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
PIXEL cellBGColor = actualBgColor;
|
|
Shinya Kitaoka |
120a6e |
double mFactor = color->m / (double)PIXEL::maxChannelValue;
|
|
Shinya Kitaoka |
120a6e |
cellBGColor.r *= mFactor;
|
|
Shinya Kitaoka |
120a6e |
cellBGColor.g *= mFactor;
|
|
Shinya Kitaoka |
120a6e |
cellBGColor.b *= mFactor;
|
|
Shinya Kitaoka |
120a6e |
cellBGColor.m *= mFactor;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
cellBuilder.doCell(cb, *color, cellBGColor, u0, v0, u1, v1);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
cellsRas->unlock();
|
|
Shinya Kitaoka |
120a6e |
ras->unlock();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
bool MosaicFx::doGetBBox(double frame, TRectD &bBox,
|
|
Shinya Kitaoka |
120a6e |
const TRenderSettings &info) {
|
|
Shinya Kitaoka |
120a6e |
// Remember: info.m_affine MUST NOT BE CONSIDERED in doGetBBox's
|
|
Shinya Kitaoka |
120a6e |
// implementation
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Retrieve the input bbox without applied affines.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (!(m_input.getFx() && m_input->doGetBBox(frame, bBox, info))) return false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Now, the grid has a given step size; the fx result is almost the same,
|
|
Shinya Kitaoka |
120a6e |
// except that it must be ceiled to the grid step.
|
|
Shinya Kitaoka |
120a6e |
double step = m_size->getValue(frame) + m_distance->getValue(frame);
|
|
Shinya Kitaoka |
120a6e |
if (!step) return true;
|
|
Shinya Kitaoka |
120a6e |
bBox = ::gridAlign(bBox, TPointD(), step);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void MosaicFx::doDryCompute(TRectD &rect, double frame,
|
|
Shinya Kitaoka |
120a6e |
const TRenderSettings &ri) {
|
|
Shinya Kitaoka |
120a6e |
if (!m_input.isConnected()) return;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double scale =
|
|
Shinya Kitaoka |
120a6e |
ri.m_affine.a11; // Legitimate due to handledAffine's implementation
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double stepD =
|
|
Shinya Kitaoka |
120a6e |
(m_size->getValue(frame) + m_distance->getValue(frame)) * scale;
|
|
Shinya Kitaoka |
120a6e |
int step = tround(stepD);
|
|
Shinya Kitaoka |
120a6e |
if (step <= 0) return;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TRectD bboxD;
|
|
Shinya Kitaoka |
120a6e |
m_input->getBBox(frame, bboxD, ri);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TRectD tileBoxD(::gridAlign(rect * bboxD, TPointD(), stepD));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TRectD srcRectD(tround(tileBoxD.x0 / stepD), tround(tileBoxD.y0 / stepD),
|
|
Shinya Kitaoka |
120a6e |
tround(tileBoxD.x1 / stepD), tround(tileBoxD.y1 / stepD));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
int enlargement =
|
|
Shinya Kitaoka |
120a6e |
(ri.m_quality == TRenderSettings::StandardResampleQuality)
|
|
Shinya Kitaoka |
120a6e |
? 1.0
|
|
Shinya Kitaoka |
120a6e |
: (ri.m_quality == TRenderSettings::ImprovedResampleQuality)
|
|
Shinya Kitaoka |
120a6e |
? 2.0
|
|
Shinya Kitaoka |
120a6e |
: (ri.m_quality == TRenderSettings::HighResampleQuality) ? 3.0
|
|
Shinya Kitaoka |
120a6e |
: 0.0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
srcRectD = srcRectD.enlarge(enlargement);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TRenderSettings riLow(ri);
|
|
Shinya Kitaoka |
120a6e |
riLow.m_affine = TScale(1.0 / stepD) * ri.m_affine;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_input->dryCompute(srcRectD, frame, riLow);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void MosaicFx::doCompute(TTile &tile, double frame, const TRenderSettings &ri) {
|
|
Shinya Kitaoka |
120a6e |
if (!m_input.isConnected()) return;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// ri's affine is the one that has already been carried due to upstream geom
|
|
Shinya Kitaoka |
120a6e |
// fxs.
|
|
Shinya Kitaoka |
120a6e |
// It is handled; so, we can transfer geometrical data directly.
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double scale =
|
|
Shinya Kitaoka |
120a6e |
ri.m_affine.a11; // Legitimate due to handledAffine's implementation
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double stepD =
|
|
Shinya Kitaoka |
120a6e |
(m_size->getValue(frame) + m_distance->getValue(frame)) * scale;
|
|
Shinya Kitaoka |
120a6e |
int step = stepD = tround(stepD);
|
|
Shinya Kitaoka |
120a6e |
if (step <= 0) {
|
|
Shinya Kitaoka |
120a6e |
// No blur will be done. The underlying fx may pass by.
|
|
Shinya Kitaoka |
120a6e |
m_input->compute(tile, frame, ri);
|
|
Shinya Kitaoka |
120a6e |
return;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double radius = 0.5 * tcrop(m_size->getValue(frame) * scale, 0.0, stepD);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TPixel32 bgcolor = m_bgcolor->getPremultipliedValue(frame);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Build the tile rect.
|
|
Shinya Kitaoka |
120a6e |
TDimension tileSize(tile.getRaster()->getSize());
|
|
Shinya Kitaoka |
120a6e |
TRectD tileRectD(tile.m_pos, TDimensionD(tileSize.lx, tileSize.ly));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Observe that TRasterFx's documentation ensures
|
|
Shinya Kitaoka |
120a6e |
// that passed tile's position is always integer, even if it's double-defined.
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Retrieve the input bbox
|
|
Shinya Kitaoka |
120a6e |
TRectD bboxD;
|
|
Shinya Kitaoka |
120a6e |
m_input->getBBox(frame, bboxD, ri);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Build the grid geometry. We require that the source tile is enlarged to
|
|
Shinya Kitaoka |
120a6e |
// cover
|
|
Shinya Kitaoka |
120a6e |
// a full grid step.
|
|
Shinya Kitaoka |
120a6e |
TRectD tileBoxD(::gridAlign(tileRectD * bboxD, TPointD(), stepD));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Now, we'll extract cell colors by computing tileBox with a res-reducing
|
|
Shinya Kitaoka |
120a6e |
// affine.
|
|
Shinya Kitaoka |
120a6e |
// So, the source tile will be
|
|
Shinya Kitaoka |
120a6e |
TRect srcRect(tround(tileBoxD.x0 / stepD), tround(tileBoxD.y0 / stepD),
|
|
Shinya Kitaoka |
120a6e |
tround(tileBoxD.x1 / stepD) - 1,
|
|
Shinya Kitaoka |
120a6e |
tround(tileBoxD.y1 / stepD) - 1);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// The calculated source rect must be enlarged by a small amount, since the
|
|
Shinya Kitaoka |
120a6e |
// resample algrotihms add some transparency to the edges.
|
|
Shinya Kitaoka |
120a6e |
int enlargement =
|
|
Shinya Kitaoka |
120a6e |
(ri.m_quality == TRenderSettings::StandardResampleQuality)
|
|
Shinya Kitaoka |
120a6e |
? 1
|
|
Shinya Kitaoka |
120a6e |
: (ri.m_quality == TRenderSettings::ImprovedResampleQuality)
|
|
Shinya Kitaoka |
120a6e |
? 2
|
|
Shinya Kitaoka |
120a6e |
: (ri.m_quality == TRenderSettings::HighResampleQuality) ? 3
|
|
Shinya Kitaoka |
120a6e |
: 0;
|
|
Shinya Kitaoka |
120a6e |
assert(enlargement > 0);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
srcRect = srcRect.enlarge(enlargement);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TRenderSettings riLow(ri);
|
|
Shinya Kitaoka |
120a6e |
riLow.m_affine = TScale(1.0 / stepD) * ri.m_affine;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Compute the input tile.
|
|
Shinya Kitaoka |
120a6e |
TRasterP srcRas(tile.getRaster()->create(srcRect.getLx(), srcRect.getLy()));
|
|
Shinya Kitaoka |
120a6e |
TTile inTile(srcRas, TPointD(srcRect.x0, srcRect.y0));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
m_input->compute(inTile, frame, riLow);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Eliminate the enlargement performed above
|
|
Shinya Kitaoka |
120a6e |
TRect r(enlargement, enlargement, srcRas->getLx() - 1 - enlargement,
|
|
Shinya Kitaoka |
120a6e |
srcRas->getLy() - 1 - enlargement);
|
|
Shinya Kitaoka |
120a6e |
srcRas = srcRas->extract(r);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Now, discriminate the tile's pixel size
|
|
Shinya Kitaoka |
120a6e |
TRaster32P srcRas32(srcRas);
|
|
Shinya Kitaoka |
120a6e |
TRaster64P srcRas64(srcRas);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TPoint pos(tround(tileBoxD.x0 - tileRectD.x0),
|
|
Shinya Kitaoka |
120a6e |
tround(tileBoxD.y0 - tileRectD.y0));
|
|
Shinya Kitaoka |
120a6e |
if (srcRas32) {
|
|
Shinya Kitaoka |
120a6e |
typedef mosaic::CellBuilder<tpixel32> cb;</tpixel32>
|
|
Shinya Kitaoka |
120a6e |
cb *cellsBuilder =
|
|
Shinya Kitaoka |
120a6e |
(m_shape->getValue() == 0)
|
|
Shinya Kitaoka |
120a6e |
? (cb *)new mosaic::SquareBuilder<tpixel32, tpixelgr8="">(</tpixel32,>
|
|
Shinya Kitaoka |
120a6e |
step, step, radius, tile.getRaster()->getWrap())
|
|
Shinya Kitaoka |
120a6e |
: (cb *)new mosaic::CircleBuilder<tpixel32, tpixelgr8="">(</tpixel32,>
|
|
Shinya Kitaoka |
120a6e |
step, step, radius, tile.getRaster()->getWrap());
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
doMosaic<tpixel32>(tile.getRaster(), srcRas32, step, pos, bgcolor,</tpixel32>
|
|
Shinya Kitaoka |
120a6e |
*cellsBuilder);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
delete cellsBuilder;
|
|
Shinya Kitaoka |
120a6e |
} else if (srcRas64) {
|
|
Shinya Kitaoka |
120a6e |
typedef mosaic::CellBuilder<tpixel64> cb;</tpixel64>
|
|
Shinya Kitaoka |
120a6e |
cb *cellsBuilder =
|
|
Shinya Kitaoka |
120a6e |
(m_shape->getValue() == 0)
|
|
Shinya Kitaoka |
120a6e |
? (cb *)new mosaic::SquareBuilder<tpixel64, tpixelgr16="">(</tpixel64,>
|
|
Shinya Kitaoka |
120a6e |
step, step, radius, tile.getRaster()->getWrap())
|
|
Shinya Kitaoka |
120a6e |
: (cb *)new mosaic::CircleBuilder<tpixel64, tpixelgr16="">(</tpixel64,>
|
|
Shinya Kitaoka |
120a6e |
step, step, radius, tile.getRaster()->getWrap());
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
doMosaic<tpixel64>(tile.getRaster(), srcRas64, step, pos, bgcolor,</tpixel64>
|
|
Shinya Kitaoka |
120a6e |
*cellsBuilder);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
delete cellsBuilder;
|
|
Shinya Kitaoka |
120a6e |
} else
|
|
Shinya Kitaoka |
120a6e |
assert(false);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
int MosaicFx::getMemoryRequirement(const TRectD &rect, double frame,
|
|
Shinya Kitaoka |
120a6e |
const TRenderSettings &info) {
|
|
Shinya Kitaoka |
120a6e |
double scale = info.m_affine.a11;
|
|
Shinya Kitaoka |
120a6e |
double stepD =
|
|
Shinya Kitaoka |
120a6e |
(m_size->getValue(frame) + m_distance->getValue(frame)) * scale;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TRectD srcRect(rect.x0 / stepD, rect.y0 / stepD, rect.x1 / stepD,
|
|
Shinya Kitaoka |
120a6e |
rect.y1 / stepD);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
return TRasterFx::memorySize(srcRect, info.m_bpp);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
FX_PLUGIN_IDENTIFIER(MosaicFx, "mosaicFx");
|