|
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 "tparamset.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
// Local namespace
|
|
Toshihiro Shimizu |
890ddd |
//************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
namespace {
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
enum PixelOp { OVER = 0, ADD, SUBTRACT, MULTIPLY, LIGHTEN, DARKEN };
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
template <typename pixel=""></typename>
|
|
Shinya Kitaoka |
120a6e |
int doBlurValue(PIXEL *SRC, int SRC_WRAP, int BLUR) {
|
|
Shinya Kitaoka |
120a6e |
unsigned int count = 0;
|
|
Shinya Kitaoka |
120a6e |
int h, k;
|
|
Shinya Kitaoka |
120a6e |
int blur_val;
|
|
Shinya Kitaoka |
120a6e |
PIXEL *pix, *line;
|
|
Shinya Kitaoka |
120a6e |
pix = line = (SRC) + (-(BLUR) + 1) * (SRC_WRAP);
|
|
Shinya Kitaoka |
120a6e |
for (h = -(BLUR) + 1; h < (BLUR); h++) {
|
|
Shinya Kitaoka |
120a6e |
for (k = -(BLUR) + 1; k < (BLUR); k++) count += pix[k].m;
|
|
Shinya Kitaoka |
120a6e |
line += SRC_WRAP;
|
|
Shinya Kitaoka |
120a6e |
pix = line;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
blur_val = (int)(count / (4 * (float)(BLUR) * (float)((BLUR)-1) + 1));
|
|
Shinya Kitaoka |
120a6e |
return blur_val;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
template <typename channel_type="" pixel,="" typename=""></typename>
|
|
Shinya Kitaoka |
120a6e |
void doBlur(CHANNEL_TYPE *greymap, const TRasterPT<pixel> &rin, int blur) {</pixel>
|
|
Shinya Kitaoka |
120a6e |
// Perform a flat mean-convolution filter
|
|
Shinya Kitaoka |
120a6e |
// NOTE: This is improved due to separability of convolution kernel, plus
|
|
Shinya Kitaoka |
120a6e |
// - since its elements are all the same, only pixels entering and quitting
|
|
Shinya Kitaoka |
120a6e |
// the convolution area are added/subtracted from the sums.
|
|
Shinya Kitaoka |
120a6e |
// As a result, this yields an O(row*columns) complexity, independently
|
|
Shinya Kitaoka |
120a6e |
// from the blur factor.
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
int i, j;
|
|
Shinya Kitaoka |
120a6e |
int blurDiameter = 2 * blur + 1;
|
|
Shinya Kitaoka |
120a6e |
unsigned long sum;
|
|
Shinya Kitaoka |
120a6e |
int wrapSrc = rin->getWrap();
|
|
Shinya Kitaoka |
120a6e |
int wrapOut = rin->getLx();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// First, blur each column independently
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// We'll need a temporary col for storing sums
|
|
Shinya Kitaoka |
120a6e |
std::unique_ptr<unsigned long[]=""> tempCol(new unsigned long[rin->getLy()]);</unsigned>
|
|
Shinya Kitaoka |
120a6e |
int edge = std::min(blur + 1, rin->getLy());
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < rin->getLx(); ++i) {
|
|
Shinya Kitaoka |
120a6e |
PIXEL *lineSrcPix = rin->pixels(0) + i;
|
|
Shinya Kitaoka |
120a6e |
CHANNEL_TYPE *lineOutPix = greymap + i;
|
|
Shinya Kitaoka |
120a6e |
PIXEL *pixin = lineSrcPix;
|
|
Shinya Kitaoka |
120a6e |
unsigned long *pixsum = tempCol.get();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
memset(tempCol.get(), 0, rin->getLy() * sizeof(unsigned long));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Build up to blur with retro-sums
|
|
Shinya Kitaoka |
120a6e |
sum = 0;
|
|
Shinya Kitaoka |
120a6e |
for (j = 0; j < edge; ++j, pixin += wrapSrc, ++pixsum) {
|
|
Shinya Kitaoka |
120a6e |
sum += pixin->m;
|
|
Shinya Kitaoka |
120a6e |
*pixsum = sum;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Fill in after blur
|
|
Shinya Kitaoka |
120a6e |
PIXEL *queuepix = lineSrcPix;
|
|
Shinya Kitaoka |
120a6e |
for (j = edge; j < rin->getLy();
|
|
Shinya Kitaoka |
120a6e |
++j, pixin += wrapSrc, queuepix += wrapSrc, ++pixsum) {
|
|
Shinya Kitaoka |
120a6e |
sum += (pixin->m - queuepix->m);
|
|
Shinya Kitaoka |
120a6e |
*pixsum = sum;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Now, the same in reverse
|
|
Shinya Kitaoka |
120a6e |
lineSrcPix = lineSrcPix + (rin->getLy() - 1) * wrapSrc;
|
|
Shinya Kitaoka |
120a6e |
pixin = lineSrcPix;
|
|
Shinya Kitaoka |
120a6e |
pixsum = tempCol.get() + rin->getLy() - 1;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
sum = 0;
|
|
Shinya Kitaoka |
120a6e |
for (j = 0; j < edge; ++j, pixin -= wrapSrc, --pixsum) {
|
|
Shinya Kitaoka |
120a6e |
*pixsum += sum;
|
|
Shinya Kitaoka |
120a6e |
sum += pixin->m;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
queuepix = lineSrcPix;
|
|
Shinya Kitaoka |
120a6e |
for (j = edge; j < rin->getLy();
|
|
Shinya Kitaoka |
120a6e |
++j, pixin -= wrapSrc, queuepix -= wrapSrc, --pixsum) {
|
|
Shinya Kitaoka |
120a6e |
sum -= queuepix->m;
|
|
Shinya Kitaoka |
120a6e |
*pixsum += sum;
|
|
Shinya Kitaoka |
120a6e |
sum += pixin->m;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Finally, transfer sums to the output greymap, divided by the blur.
|
|
Shinya Kitaoka |
120a6e |
pixsum = tempCol.get();
|
|
Shinya Kitaoka |
120a6e |
CHANNEL_TYPE *pixout = lineOutPix;
|
|
Shinya Kitaoka |
120a6e |
for (j = 0; j < rin->getLy(); ++j, pixout += wrapOut, ++pixsum)
|
|
Shinya Kitaoka |
120a6e |
*pixout = (*pixsum) / blurDiameter;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Then, the same for all greymap rows
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// We'll need a temporary row for sums
|
|
Shinya Kitaoka |
120a6e |
std::unique_ptr<unsigned long[]=""> tempRow(new unsigned long[rin->getLx()]);</unsigned>
|
|
Shinya Kitaoka |
120a6e |
edge = std::min(blur + 1, rin->getLx());
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (j = 0; j < rin->getLy(); ++j) {
|
|
Shinya Kitaoka |
120a6e |
CHANNEL_TYPE *lineSrcPix = greymap + j * wrapOut;
|
|
Shinya Kitaoka |
120a6e |
CHANNEL_TYPE *lineOutPix = lineSrcPix;
|
|
Shinya Kitaoka |
120a6e |
unsigned long *pixsum = tempRow.get();
|
|
Shinya Kitaoka |
120a6e |
CHANNEL_TYPE *pixin = lineSrcPix;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
memset(tempRow.get(), 0, rin->getLx() * sizeof(unsigned long));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Build up to blur with retro-sums
|
|
Shinya Kitaoka |
120a6e |
sum = 0;
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < edge; ++i, ++pixin, ++pixsum) {
|
|
Shinya Kitaoka |
120a6e |
sum += *pixin;
|
|
Shinya Kitaoka |
120a6e |
*pixsum = sum;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Fill in after blur
|
|
Shinya Kitaoka |
120a6e |
CHANNEL_TYPE *queuepix = lineSrcPix;
|
|
Shinya Kitaoka |
120a6e |
for (i = edge; i < rin->getLx(); ++i, ++pixin, ++pixsum, ++queuepix) {
|
|
Shinya Kitaoka |
120a6e |
sum += *pixin;
|
|
Shinya Kitaoka |
120a6e |
sum -= *queuepix;
|
|
Shinya Kitaoka |
120a6e |
*pixsum = sum;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Now, the same in reverse
|
|
Shinya Kitaoka |
120a6e |
lineSrcPix = lineSrcPix + rin->getLx() - 1;
|
|
Shinya Kitaoka |
120a6e |
pixin = lineSrcPix;
|
|
Shinya Kitaoka |
120a6e |
pixsum = tempRow.get() + rin->getLx() - 1;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
sum = 0;
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < edge; ++i, --pixin, --pixsum) {
|
|
Shinya Kitaoka |
120a6e |
*pixsum += sum;
|
|
Shinya Kitaoka |
120a6e |
sum += *pixin;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
queuepix = lineSrcPix;
|
|
Shinya Kitaoka |
120a6e |
for (i = edge; i < rin->getLx(); ++i, --pixin, --pixsum, --queuepix) {
|
|
Shinya Kitaoka |
120a6e |
sum -= *queuepix;
|
|
Shinya Kitaoka |
120a6e |
*pixsum += sum;
|
|
Shinya Kitaoka |
120a6e |
sum += *pixin;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Finally, transfer sums to the output greymap, divided by the blur.
|
|
Shinya Kitaoka |
120a6e |
CHANNEL_TYPE *pixout = lineOutPix;
|
|
Shinya Kitaoka |
120a6e |
pixsum = tempRow.get();
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < rin->getLx(); ++i, ++pixout, ++pixsum)
|
|
Shinya Kitaoka |
120a6e |
*pixout = (*pixsum) / blurDiameter;
|
|
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 myOver(PIXEL &pixout, const PIXEL &pixin, const PIXEL &color) {
|
|
Shinya Kitaoka |
120a6e |
pixout = color;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
template <typename pixel=""></typename>
|
|
Shinya Kitaoka |
120a6e |
void myAdd(PIXEL &pixout, const PIXEL &pixin, const PIXEL &color) {
|
|
Shinya Kitaoka |
120a6e |
pixout.r = std::min(pixin.r + color.r, PIXEL::maxChannelValue);
|
|
Shinya Kitaoka |
120a6e |
pixout.g = std::min(pixin.g + color.g, PIXEL::maxChannelValue);
|
|
Shinya Kitaoka |
120a6e |
pixout.b = std::min(pixin.b + color.b, PIXEL::maxChannelValue);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
template <typename pixel=""></typename>
|
|
Shinya Kitaoka |
120a6e |
void mySub(PIXEL &pixout, const PIXEL &pixin, const PIXEL &color) {
|
|
Shinya Kitaoka |
120a6e |
pixout.r = std::max(pixin.r - color.r, 0);
|
|
Shinya Kitaoka |
120a6e |
pixout.g = std::max(pixin.g - color.g, 0);
|
|
Shinya Kitaoka |
120a6e |
pixout.b = std::max(pixin.b - color.b, 0);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
template <typename pixel=""></typename>
|
|
Shinya Kitaoka |
120a6e |
void myMult(PIXEL &pixout, const PIXEL &pixin, const PIXEL &color) {
|
|
Shinya Kitaoka |
120a6e |
static const double den = PIXEL::maxChannelValue;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
pixout.r = pixin.r * (color.r / den);
|
|
Shinya Kitaoka |
120a6e |
pixout.g = pixin.g * (color.g / den);
|
|
Shinya Kitaoka |
120a6e |
pixout.b = pixin.b * (color.b / den);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
template <typename pixel=""></typename>
|
|
Shinya Kitaoka |
120a6e |
void myLighten(PIXEL &pixout, const PIXEL &pixin, const PIXEL &color) {
|
|
Shinya Kitaoka |
120a6e |
pixout.r = pixin.r > color.r ? pixin.r : color.r;
|
|
Shinya Kitaoka |
120a6e |
pixout.g = pixin.g > color.g ? pixin.g : color.g;
|
|
Shinya Kitaoka |
120a6e |
pixout.b = pixin.b > color.b ? pixin.b : color.b;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
template <typename pixel=""></typename>
|
|
Shinya Kitaoka |
120a6e |
void myDarken(PIXEL &pixout, const PIXEL &pixin, const PIXEL &color) {
|
|
Shinya Kitaoka |
120a6e |
pixout.r = pixin.r < color.r ? pixin.r : color.r;
|
|
Shinya Kitaoka |
120a6e |
pixout.g = pixin.g < color.g ? pixin.g : color.g;
|
|
Shinya Kitaoka |
120a6e |
pixout.b = pixin.b < color.b ? pixin.b : color.b;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
template <typename channel="" pixel,="" typename=""></typename>
|
|
Shinya Kitaoka |
120a6e |
void doLayerBlending(PIXEL *pixin, PIXEL *pixout, CHANNEL *pixmatte, int inLx,
|
|
Shinya Kitaoka |
120a6e |
int outLx, int outLy, int wrapIn, int wrapOut, int dx,
|
|
Shinya Kitaoka |
120a6e |
int dy, double transp, PIXEL color,
|
|
Shinya Kitaoka |
120a6e |
void (*pixelOp)(PIXEL &, const PIXEL &, const PIXEL &)) {
|
|
Shinya Kitaoka |
120a6e |
double CROP_VAL = PIXEL::maxChannelValue;
|
|
Shinya Kitaoka |
120a6e |
CHANNEL U_CROP_VAL = PIXEL::maxChannelValue;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
int const_transp = CROP_VAL * transp + 0.5;
|
|
Shinya Kitaoka |
120a6e |
double val_r, val_g, val_b, val_m;
|
|
Shinya Kitaoka |
120a6e |
int blur_val;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
PIXEL opColor;
|
|
Shinya Kitaoka |
120a6e |
double k, matte;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
CHANNEL shadow_matte;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
int x, y;
|
|
Shinya Kitaoka |
120a6e |
for (y = 0; y < outLy; ++y, pixin += wrapIn - outLx,
|
|
Shinya Kitaoka |
120a6e |
pixout += wrapOut - outLx, pixmatte += inLx - outLx)
|
|
Shinya Kitaoka |
120a6e |
for (x = 0; x < outLx; ++x, ++pixin, ++pixout, ++pixmatte) {
|
|
Shinya Kitaoka |
120a6e |
if (pixin->m != 0) // where the image is transparent, no shadow
|
|
Shinya Kitaoka |
120a6e |
{
|
|
Shinya Kitaoka |
120a6e |
blur_val = *(pixmatte + dy * inLx + dx);
|
|
Shinya Kitaoka |
120a6e |
shadow_matte = (blur_val) ? (int)((CROP_VAL - blur_val) * transp + 0.5)
|
|
Shinya Kitaoka |
120a6e |
: const_transp;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
k = (double)(CROP_VAL - shadow_matte) / CROP_VAL;
|
|
Shinya Kitaoka |
120a6e |
val_r = pixin->r * k + 0.5;
|
|
Shinya Kitaoka |
120a6e |
val_g = pixin->g * k + 0.5;
|
|
Shinya Kitaoka |
120a6e |
val_b = pixin->b * k + 0.5;
|
|
Shinya Kitaoka |
120a6e |
val_m = pixin->m;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
pixelOp(opColor, *pixin, color);
|
|
Shinya Kitaoka |
120a6e |
matte = (1 - k) * (val_m / CROP_VAL);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
val_r += matte * opColor.r;
|
|
Shinya Kitaoka |
120a6e |
val_g += matte * opColor.g;
|
|
Shinya Kitaoka |
120a6e |
val_b += matte * opColor.b;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
pixout->r = (val_r > CROP_VAL) ? U_CROP_VAL
|
|
Shinya Kitaoka |
120a6e |
: ((val_r < 0) ? 0 : (CHANNEL)val_r);
|
|
Shinya Kitaoka |
120a6e |
pixout->g = (val_g > CROP_VAL) ? U_CROP_VAL
|
|
Shinya Kitaoka |
120a6e |
: ((val_g < 0) ? 0 : (CHANNEL)val_g);
|
|
Shinya Kitaoka |
120a6e |
pixout->b = (val_b > CROP_VAL) ? U_CROP_VAL
|
|
Shinya Kitaoka |
120a6e |
: ((val_b < 0) ? 0 : (CHANNEL)val_b);
|
|
Shinya Kitaoka |
120a6e |
pixout->m = (val_m > CROP_VAL) ? U_CROP_VAL
|
|
Shinya Kitaoka |
120a6e |
: ((val_m < 0) ? 0 : (CHANNEL)val_m);
|
|
Shinya Kitaoka |
120a6e |
} else
|
|
Shinya Kitaoka |
120a6e |
*pixout = PIXEL::Transparent;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
template <typename pixel=""></typename>
|
|
Toshihiro Shimizu |
890ddd |
void doBodyHighlight(const TRasterPT<pixel> rout, const TRasterPT<pixel> rin,</pixel></pixel>
|
|
Shinya Kitaoka |
120a6e |
TRectD rectIn, int rasInLx, int rasInLy, double frame,
|
|
Shinya Kitaoka |
120a6e |
int blur, double transp, PIXEL color, TPointD point,
|
|
Shinya Kitaoka |
120a6e |
bool invert,
|
|
Shinya Kitaoka |
120a6e |
void (*pixelOp)(PIXEL &, const PIXEL &, const PIXEL &),
|
|
Shinya Kitaoka |
120a6e |
TRasterFxPort &m_input, const TRenderSettings &ri) {
|
|
Shinya Kitaoka |
120a6e |
typedef typename PIXEL::Channel CHANNEL_TYPE;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
rin->lock();
|
|
Shinya Kitaoka |
120a6e |
rout->lock();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
int inLx = rin->getLx(), inLy = rin->getLy(), inWrap = rin->getWrap();
|
|
Shinya Kitaoka |
120a6e |
int outLx = rout->getLx(), outLy = rout->getLy(), outWrap = rout->getWrap();
|
|
Shinya Kitaoka |
120a6e |
int dx = point.x, dy = point.y;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
transp = 1.0 - transp;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
PIXEL *src_buf, *dst_buf;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
dst_buf = rout->pixels(0);
|
|
Shinya Kitaoka |
120a6e |
src_buf = rin->pixels(0) + blur + blur * inWrap;
|
|
Shinya Kitaoka |
120a6e |
if (dy < 0) src_buf -= dy * inWrap;
|
|
Shinya Kitaoka |
120a6e |
if (dx < 0) src_buf -= dx;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// First, perform an optimized mean-convolution of the interesting part of
|
|
Shinya Kitaoka |
120a6e |
// image's matte
|
|
Shinya Kitaoka |
120a6e |
int matteLxLy = inLx * inLy;
|
|
Shinya Kitaoka |
120a6e |
CHANNEL_TYPE *matteGreymap =
|
|
Shinya Kitaoka |
120a6e |
(CHANNEL_TYPE *)malloc(matteLxLy * sizeof(CHANNEL_TYPE));
|
|
Shinya Kitaoka |
120a6e |
if (!matteGreymap) return;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
memset(matteGreymap, 0, matteLxLy * sizeof(CHANNEL_TYPE));
|
|
Shinya Kitaoka |
120a6e |
doBlur<pixel, channel_type="">(matteGreymap, rin, blur);</pixel,>
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
CHANNEL_TYPE U_CROP_VAL = PIXEL::maxChannelValue;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// If specified, invert the matte
|
|
Shinya Kitaoka |
120a6e |
if (invert) {
|
|
Shinya Kitaoka |
120a6e |
CHANNEL_TYPE *mpix, *end = matteGreymap + matteLxLy;
|
|
Shinya Kitaoka |
120a6e |
for (mpix = matteGreymap; mpix < end; ++mpix) *mpix = U_CROP_VAL - *mpix;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
CHANNEL_TYPE *mattepix = matteGreymap + blur + blur * inLx;
|
|
Shinya Kitaoka |
120a6e |
if (dy < 0) mattepix -= dy * inLx;
|
|
Shinya Kitaoka |
120a6e |
if (dx < 0) mattepix -= dx;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
doLayerBlending(src_buf, dst_buf, mattepix, inLx, outLx, outLy, inWrap,
|
|
Shinya Kitaoka |
120a6e |
outWrap, dx, dy, transp, color, pixelOp);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
free(matteGreymap);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
rin->unlock();
|
|
Shinya Kitaoka |
120a6e |
rout->unlock();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
} // namespace
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
// BodyHighLightFx implementation
|
|
Toshihiro Shimizu |
890ddd |
//************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
d1f6c4 |
class BodyHighLightFx final : public TStandardRasterFx {
|
|
Shinya Kitaoka |
120a6e |
FX_PLUGIN_DECLARATION(BodyHighLightFx)
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TRasterFxPort m_input;
|
|
Shinya Kitaoka |
120a6e |
TIntEnumParamP m_mode;
|
|
Shinya Kitaoka |
120a6e |
TPointParamP m_point;
|
|
Shinya Kitaoka |
120a6e |
TDoubleParamP m_transparency;
|
|
Shinya Kitaoka |
120a6e |
TDoubleParamP m_blur;
|
|
Shinya Kitaoka |
120a6e |
TPixelParamP m_color;
|
|
Shinya Kitaoka |
120a6e |
TBoolParamP m_invert;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
BodyHighLightFx()
|
|
Shinya Kitaoka |
120a6e |
: m_point(TPointD(10.0, 10.0))
|
|
Shinya Kitaoka |
120a6e |
, m_mode(new TIntEnumParam(OVER, "Over"))
|
|
Shinya Kitaoka |
120a6e |
, m_transparency(0.5)
|
|
Shinya Kitaoka |
120a6e |
, m_blur(2.0)
|
|
Shinya Kitaoka |
120a6e |
, m_color(TPixel32::White)
|
|
Shinya Kitaoka |
120a6e |
, m_invert(false) {
|
|
Shinya Kitaoka |
120a6e |
m_point->getX()->setMeasureName("fxLength");
|
|
Shinya Kitaoka |
120a6e |
m_point->getY()->setMeasureName("fxLength");
|
|
Shinya Kitaoka |
120a6e |
m_blur->setMeasureName("fxLength");
|
|
Shinya Kitaoka |
120a6e |
bindParam(this, "mode", m_mode);
|
|
Shinya Kitaoka |
120a6e |
bindParam(this, "point", m_point);
|
|
Shinya Kitaoka |
120a6e |
bindParam(this, "transparency", m_transparency);
|
|
Shinya Kitaoka |
120a6e |
bindParam(this, "blur", m_blur);
|
|
Shinya Kitaoka |
120a6e |
bindParam(this, "color", m_color);
|
|
Shinya Kitaoka |
120a6e |
bindParam(this, "invert", m_invert);
|
|
Shinya Kitaoka |
120a6e |
addInputPort("Source", m_input);
|
|
Shinya Kitaoka |
120a6e |
m_transparency->setValueRange(0.0, 1.0);
|
|
Shinya Kitaoka |
120a6e |
m_blur->setValueRange(0, (std::numeric_limits<double>::max)());</double>
|
|
Shinya Kitaoka |
120a6e |
m_color->enableMatte(false);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
m_mode->addItem(ADD, "Add");
|
|
Shinya Kitaoka |
120a6e |
m_mode->addItem(SUBTRACT, "Subtract");
|
|
Shinya Kitaoka |
120a6e |
m_mode->addItem(MULTIPLY, "Multiply");
|
|
Shinya Kitaoka |
120a6e |
m_mode->addItem(LIGHTEN, "Lighten");
|
|
Shinya Kitaoka |
120a6e |
m_mode->addItem(DARKEN, "Darken");
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
~BodyHighLightFx(){};
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
38fd86 |
bool doGetBBox(double frame, TRectD &bBox,
|
|
Shinya Kitaoka |
38fd86 |
const TRenderSettings &info) override {
|
|
Shinya Kitaoka |
120a6e |
if (m_input.isConnected())
|
|
Shinya Kitaoka |
120a6e |
return m_input->doGetBBox(frame, bBox, info);
|
|
Shinya Kitaoka |
120a6e |
else {
|
|
Shinya Kitaoka |
120a6e |
bBox = TRectD();
|
|
Shinya Kitaoka |
120a6e |
return false;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
38fd86 |
bool canHandle(const TRenderSettings &info, double frame) override {
|
|
Shinya Kitaoka |
38fd86 |
return true;
|
|
Shinya Kitaoka |
38fd86 |
}
|
|
Shinya Kitaoka |
38fd86 |
void doDryCompute(TRectD &rect, double frame,
|
|
Shinya Kitaoka |
38fd86 |
const TRenderSettings &info) override;
|
|
Shinya Kitaoka |
473e70 |
void doCompute(TTile &tile, double frame, const TRenderSettings &) override;
|
|
Shinya Kitaoka |
120a6e |
int getMemoryRequirement(const TRectD &rect, double frame,
|
|
Shinya Kitaoka |
473e70 |
const TRenderSettings &info) override;
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void BodyHighLightFx::doDryCompute(TRectD &rect, double frame,
|
|
Shinya Kitaoka |
120a6e |
const TRenderSettings &info) {
|
|
Shinya Kitaoka |
120a6e |
m_input->dryCompute(rect, frame, info);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double fac = sqrt(fabs(info.m_affine.det()));
|
|
Shinya Kitaoka |
120a6e |
int blur = (int)(fac * fabs(m_blur->getValue(frame)));
|
|
Shinya Kitaoka |
120a6e |
TPoint point = convert(fac * m_point->getValue(frame));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TRectD rectIn = rect.enlarge(blur);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
int rasInLx = tround(rectIn.getLx() + abs(point.x)) + 1;
|
|
Shinya Kitaoka |
120a6e |
int rasInLy = tround(rectIn.getLy() + abs(point.y)) + 1;
|
|
Shinya Kitaoka |
120a6e |
if (point.x < 0) {
|
|
Shinya Kitaoka |
120a6e |
rectIn.x0 += point.x;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
if (point.y < 0) {
|
|
Shinya Kitaoka |
120a6e |
rectIn.y0 += point.y;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
rectIn = TRectD(rectIn.getP00(), TDimensionD(rasInLx, rasInLy));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_input->dryCompute(rectIn, frame, info);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void BodyHighLightFx::doCompute(TTile &tile, double frame,
|
|
Shinya Kitaoka |
120a6e |
const TRenderSettings &ri) {
|
|
Shinya Kitaoka |
120a6e |
double fac = sqrt(fabs(ri.m_affine.det()));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (!m_input.isConnected()) return;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Compute the effective input tile
|
|
Shinya Kitaoka |
120a6e |
m_input->compute(tile, frame, ri);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double transp = m_transparency->getValue(frame);
|
|
Shinya Kitaoka |
120a6e |
int blur = (int)(fac * fabs(m_blur->getValue(frame)));
|
|
Shinya Kitaoka |
120a6e |
TPoint point = convert(fac * m_point->getValue(frame));
|
|
Shinya Kitaoka |
120a6e |
bool invert = m_invert->getValue();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Build the shadow, blurred tile
|
|
Shinya Kitaoka |
120a6e |
TDimension rectSize(tile.getRaster()->getSize());
|
|
Shinya Kitaoka |
120a6e |
TRectD rectIn(tile.m_pos, TDimensionD(rectSize.lx, rectSize.ly));
|
|
Shinya Kitaoka |
120a6e |
rectIn = rectIn.enlarge(blur);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Shift rectIn by the input 'point'
|
|
Shinya Kitaoka |
120a6e |
int rasInLx = tround(rectIn.getLx() + abs(point.x)) + 1;
|
|
Shinya Kitaoka |
120a6e |
int rasInLy = tround(rectIn.getLy() + abs(point.y)) + 1;
|
|
Shinya Kitaoka |
120a6e |
if (point.x < 0) {
|
|
Shinya Kitaoka |
120a6e |
rectIn.x0 += point.x;
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
rectIn.x1 += point.x;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
if (point.y < 0) {
|
|
Shinya Kitaoka |
120a6e |
rectIn.y0 += point.y;
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
rectIn.y1 += point.y;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
const TPixel32 color = m_color->getPremultipliedValue(frame);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TRaster32P raster32 = tile.getRaster();
|
|
Shinya Kitaoka |
120a6e |
TRaster64P raster64 = tile.getRaster();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TTile tileIn;
|
|
Shinya Kitaoka |
120a6e |
m_input->allocateAndCompute(tileIn, rectIn.getP00(),
|
|
Shinya Kitaoka |
120a6e |
TDimension(rasInLx, rasInLy), tile.getRaster(),
|
|
Shinya Kitaoka |
120a6e |
frame, ri);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Select the specified pixel operation
|
|
Shinya Kitaoka |
120a6e |
void (*pixelOp32)(TPixel32 &, const TPixel32 &, const TPixel32 &);
|
|
Shinya Kitaoka |
120a6e |
void (*pixelOp64)(TPixel64 &, const TPixel64 &, const TPixel64 &);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
switch (m_mode->getValue()) {
|
|
Shinya Kitaoka |
120a6e |
case OVER: {
|
|
Shinya Kitaoka |
120a6e |
pixelOp32 = ::myOver<tpixel32>;</tpixel32>
|
|
Shinya Kitaoka |
120a6e |
pixelOp64 = ::myOver<tpixel64>;</tpixel64>
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
case ADD: {
|
|
Shinya Kitaoka |
120a6e |
pixelOp32 = ::myAdd<tpixel32>;</tpixel32>
|
|
Shinya Kitaoka |
120a6e |
pixelOp64 = ::myAdd<tpixel64>;</tpixel64>
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
case SUBTRACT: {
|
|
Shinya Kitaoka |
120a6e |
pixelOp32 = ::mySub<tpixel32>;</tpixel32>
|
|
Shinya Kitaoka |
120a6e |
pixelOp64 = ::mySub<tpixel64>;</tpixel64>
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
case MULTIPLY: {
|
|
Shinya Kitaoka |
120a6e |
pixelOp32 = ::myMult<tpixel32>;</tpixel32>
|
|
Shinya Kitaoka |
120a6e |
pixelOp64 = ::myMult<tpixel64>;</tpixel64>
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
case LIGHTEN: {
|
|
Shinya Kitaoka |
120a6e |
pixelOp32 = ::myLighten<tpixel32>;</tpixel32>
|
|
Shinya Kitaoka |
120a6e |
pixelOp64 = ::myLighten<tpixel64>;</tpixel64>
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
case DARKEN: {
|
|
Shinya Kitaoka |
120a6e |
pixelOp32 = ::myDarken<tpixel32>;</tpixel32>
|
|
Shinya Kitaoka |
120a6e |
pixelOp64 = ::myDarken<tpixel64>;</tpixel64>
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TRaster32P rin = tileIn.getRaster();
|
|
Shinya Kitaoka |
120a6e |
if (raster32)
|
|
Shinya Kitaoka |
120a6e |
doBodyHighlight<tpixel32>(raster32, rin, rectIn, rasInLx, rasInLy, frame,</tpixel32>
|
|
Shinya Kitaoka |
120a6e |
blur, transp, color, convert(point), invert,
|
|
Shinya Kitaoka |
120a6e |
pixelOp32, m_input, ri);
|
|
Shinya Kitaoka |
120a6e |
else {
|
|
Shinya Kitaoka |
120a6e |
TRaster64P rin = tileIn.getRaster();
|
|
Shinya Kitaoka |
120a6e |
if (raster64)
|
|
Shinya Kitaoka |
120a6e |
doBodyHighlight<tpixel64>(raster64, rin, rectIn, rasInLx, rasInLy, frame,</tpixel64>
|
|
Shinya Kitaoka |
120a6e |
blur, transp, toPixel64(color), convert(point),
|
|
Shinya Kitaoka |
120a6e |
invert, pixelOp64, m_input, ri);
|
|
Shinya Kitaoka |
120a6e |
else
|
|
Shinya Kitaoka |
120a6e |
throw TException("Brightness&Contrast: unsupported Pixel Type");
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
int BodyHighLightFx::getMemoryRequirement(const TRectD &rect, double frame,
|
|
Shinya Kitaoka |
120a6e |
const TRenderSettings &info) {
|
|
Shinya Kitaoka |
120a6e |
int blur =
|
|
Shinya Kitaoka |
120a6e |
(int)(sqrt(fabs(info.m_affine.det())) * fabs(m_blur->getValue(frame)));
|
|
Shinya Kitaoka |
120a6e |
return TRasterFx::memorySize(rect.enlarge(blur), info.m_bpp);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
FX_PLUGIN_IDENTIFIER(BodyHighLightFx, "bodyHighLightFx")
|