diff --git a/stuff/config/current.txt b/stuff/config/current.txt
index 1bf1c92..726d3fe 100644
--- a/stuff/config/current.txt
+++ b/stuff/config/current.txt
@@ -1350,8 +1350,12 @@
- "STD_iwa_BloomFx" "Bloom Iwa"
- "STD_iwa_BloomFx.gamma" "Gamma"
+ - "STD_iwa_BloomFx.auto_gain" "Auto Gain"
+ - "STD_iwa_BloomFx.gain_adjust" "Gain Adjustment"
- "STD_iwa_BloomFx.gain" "Gain"
+ - "STD_iwa_BloomFx.decay" "Decay"
- "STD_iwa_BloomFx.size" "Size"
+ - "STD_iwa_BloomFx.alpha_mode" "Alpha Mode"
- "STD_iwa_BloomFx.alpha_rendering" "Alpha Rendering"
diff --git a/stuff/profiles/layouts/fxs/STD_iwa_BloomFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_BloomFx.xml
index ae3daec..f6c57bf 100644
--- a/stuff/profiles/layouts/fxs/STD_iwa_BloomFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_iwa_BloomFx.xml
@@ -1,8 +1,16 @@
gamma
+ auto_gain
+ gain_adjust
gain
+ decay
size
- alpha_rendering
+ alpha_mode
+
+ auto_gain
+ gain_adjust
+ gain
+
diff --git a/toonz/sources/include/toonzqt/paramfield.h b/toonz/sources/include/toonzqt/paramfield.h
index fc621fa..43bbb7e 100644
--- a/toonz/sources/include/toonzqt/paramfield.h
+++ b/toonz/sources/include/toonzqt/paramfield.h
@@ -370,6 +370,7 @@ public:
void updateField(double value) override;
QSize getPreferedSize() override { return QSize(260, 28); }
+ void setPrecision(int precision) override;
protected slots:
void onChange(bool);
diff --git a/toonz/sources/stdfx/iwa_bloomfx.cpp b/toonz/sources/stdfx/iwa_bloomfx.cpp
index 7b0e199..c4643d9 100644
--- a/toonz/sources/stdfx/iwa_bloomfx.cpp
+++ b/toonz/sources/stdfx/iwa_bloomfx.cpp
@@ -52,15 +52,36 @@ void blurByRotate(cv::Mat &mat) {
// Iwa_BloomFx
//--------------------------------------------
Iwa_BloomFx::Iwa_BloomFx()
- : m_gamma(2.2), m_gain(2.0), m_size(100.0), m_alpha_rendering(false) {
+ : m_gamma(2.2)
+ , m_auto_gain(false)
+ , m_gain_adjust(0.0)
+ , m_gain(2.0)
+ , m_decay(1)
+ , m_size(100.0)
+ , m_alpha_rendering(false)
+ , m_alpha_mode(new TIntEnumParam(NoAlpha, "No Alpha")) {
+ // Version 1 : gaussian filter applied with standard deviation 0
+ // Version 2 : standard deviation = blurRadius * 0.3
+ setFxVersion(2);
+
addInputPort("Source", m_source);
bindParam(this, "gamma", m_gamma);
+ bindParam(this, "auto_gain", m_auto_gain);
+ bindParam(this, "gain_adjust", m_gain_adjust);
bindParam(this, "gain", m_gain);
+ bindParam(this, "decay", m_decay);
bindParam(this, "size", m_size);
- bindParam(this, "alpha_rendering", m_alpha_rendering);
+ bindParam(this, "alpha_mode", m_alpha_mode);
+ bindParam(this, "alpha_rendering", m_alpha_rendering, false,
+ true); // obsolete
+
+ m_alpha_mode->addItem(Light, "Light");
+ m_alpha_mode->addItem(LightAndSource, "Light and Source");
m_gamma->setValueRange(0.1, 5.0);
+ m_gain_adjust->setValueRange(-1.0, 1.0);
m_gain->setValueRange(0.1, 10.0);
+ m_decay->setValueRange(0, 4);
m_size->setValueRange(0.1, 1024.0);
m_size->setMeasureName("fxLength");
@@ -111,12 +132,12 @@ void Iwa_BloomFx::setSourceTileToMat(const RASTER ras, cv::Mat &imgMat,
//------------------------------------------------
template
void Iwa_BloomFx::setMatToOutput(const RASTER ras, const RASTER srcRas,
- cv::Mat &ingMat, const double gamma,
- const double gain, const bool withAlpha,
+ cv::Mat &imgMat, const double gamma,
+ const double gain, const AlphaMode alphaMode,
const int margin) {
double maxi = static_cast(PIXEL::maxChannelValue); // 255or65535
for (int j = 0; j < ras->getLy(); j++) {
- cv::Vec3f const *mat_p = ingMat.ptr(j);
+ cv::Vec3f const *mat_p = imgMat.ptr(j);
PIXEL *pix = ras->pixels(j);
PIXEL *srcPix = srcRas->pixels(j + margin) + margin;
@@ -135,15 +156,36 @@ void Iwa_BloomFx::setMatToOutput(const RASTER ras, const RASTER srcRas,
pix->r = (typename PIXEL::Channel)(nonlinear_r * (maxi + 0.999999));
pix->g = (typename PIXEL::Channel)(nonlinear_g * (maxi + 0.999999));
pix->b = (typename PIXEL::Channel)(nonlinear_b * (maxi + 0.999999));
- if (withAlpha) {
+ if (alphaMode == NoAlpha)
+ pix->m = (typename PIXEL::Channel)(PIXEL::maxChannelValue);
+ else {
double chan_a =
std::max(std::max(nonlinear_b, nonlinear_g), nonlinear_r);
- pix->m = std::max((typename PIXEL::Channel)(chan_a * (maxi + 0.999999)),
- srcPix->m);
- } else
- pix->m = (typename PIXEL::Channel)(PIXEL::maxChannelValue);
+ if (alphaMode == Light)
+ pix->m = (typename PIXEL::Channel)(chan_a * (maxi + 0.999999));
+ else // alphaMode == LightAndSource
+ pix->m = std::max(
+ (typename PIXEL::Channel)(chan_a * (maxi + 0.999999)), srcPix->m);
+ }
+ }
+ }
+}
+
+//------------------------------------------------
+
+double Iwa_BloomFx::computeAutoGain(cv::Mat &imgMat) {
+ double maxChanelValue = 0.0;
+ for (int j = 0; j < imgMat.size().height; j++) {
+ cv::Vec3f const *mat_p = imgMat.ptr(j);
+ for (int i = 0; i < imgMat.size().width; i++, mat_p++) {
+ for (int c = 0; c < 3; c++)
+ maxChanelValue = std::max(maxChanelValue, (double)(*mat_p)[c]);
}
}
+
+ if (maxChanelValue == 0.0) return 1.0;
+
+ return 1.0 / maxChanelValue;
}
//------------------------------------------------
@@ -156,10 +198,14 @@ void Iwa_BloomFx::doCompute(TTile &tile, double frame,
return;
}
// obtain parameters
- double gamma = m_gamma->getValue(frame);
- double gain = m_gain->getValue(frame);
- double size = getSizePixelAmount(m_size->getValue(frame), settings.m_affine);
- bool withAlpha = m_alpha_rendering->getValue();
+ double gamma = m_gamma->getValue(frame);
+ bool autoGain = m_auto_gain->getValue();
+ double gainAdjust =
+ (autoGain) ? std::pow(10.0, m_gain_adjust->getValue(frame)) : 1.0;
+ double gain = (autoGain) ? 1.0 : m_gain->getValue(frame);
+ int blurRadius = (int)std::round(m_decay->getValue(frame));
+ double size = getSizePixelAmount(m_size->getValue(frame), settings.m_affine);
+ AlphaMode alphaMode = (AlphaMode)m_alpha_mode->getValue();
int margin = static_cast(std::ceil(size));
TRectD _rect(tile.m_pos, TDimensionD(tile.getRaster()->getLx(),
@@ -187,7 +233,8 @@ void Iwa_BloomFx::doCompute(TTile &tile, double frame,
// compute size and intensity ratios of resampled layers
// resample size is reduced from the specified size, taking into account
// that the gaussian blur (x 2) and the blur by rotation resampling (x sqrt2)
- double no_blur_size = size / (2 * 1.5);
+ double blurScale = 1.0 + (double)blurRadius;
+ double no_blur_size = size / (blurScale * 1.5);
// find the mimimum "power of 2" value which is the same as or larger than the
// filter size
int level = 1;
@@ -195,7 +242,7 @@ void Iwa_BloomFx::doCompute(TTile &tile, double frame,
while (1) {
if (power_of_2 >= no_blur_size) break;
level++;
- power_of_2 *= 2.0;
+ power_of_2 *= 2;
}
// store the size of resampled layers
QVector sizes;
@@ -221,7 +268,9 @@ void Iwa_BloomFx::doCompute(TTile &tile, double frame,
double intensity_front = 1.0 - (1.0 - intensity_all) * ratio;
std::vector dst(level);
- cv::Size const ksize(3, 3);
+ cv::Size const ksize(1 + blurRadius * 2, 1 + blurRadius * 2);
+ // standard deviation
+ double sdRatio = (getFxVersion() == 1) ? 0.0 : 0.3;
cv::Mat tmp;
int i;
@@ -233,7 +282,10 @@ void Iwa_BloomFx::doCompute(TTile &tile, double frame,
imgMat = tmp;
}
// gaussian blur
- cv::GaussianBlur(imgMat, dst[i], ksize, 0.0);
+ if (blurRadius == 0)
+ dst[i] = imgMat;
+ else
+ cv::GaussianBlur(imgMat, dst[i], ksize, (double)blurRadius * sdRatio);
++i;
}
// for each level of filter (from smaller to larger)
@@ -254,15 +306,20 @@ void Iwa_BloomFx::doCompute(TTile &tile, double frame,
cv::Size(tile.getRaster()->getLx(), tile.getRaster()->getLy()));
imgMat = imgMat(roi);
+ if (autoGain) {
+ gain =
+ to_linear_color_space(gainAdjust, 1.0, gamma) * computeAutoGain(imgMat);
+ }
+
// set the result to the tile, converting to rgb channel values
if (ras32)
setMatToOutput(tile.getRaster(),
sourceTile.getRaster(), imgMat, gamma,
- gain, withAlpha, margin);
+ gain, alphaMode, margin);
else if (ras64)
setMatToOutput(tile.getRaster(),
sourceTile.getRaster(), imgMat, gamma,
- gain, withAlpha, margin);
+ gain, alphaMode, margin);
}
//------------------------------------------------
@@ -295,5 +352,15 @@ void Iwa_BloomFx::getParamUIs(TParamUIConcept *&concepts, int &length) {
concepts[0].m_params.push_back(m_size);
}
//------------------------------------------------
+// This will be called in TFx::loadData when obsolete "alpha rendering" value is
+// loaded
+void Iwa_BloomFx::onObsoleteParamLoaded(const std::string ¶mName) {
+ if (paramName != "alpha_rendering") return;
+ if (m_alpha_rendering->getValue())
+ m_alpha_mode->setValue(LightAndSource);
+ else
+ m_alpha_mode->setValue(NoAlpha);
+}
+//------------------------------------------------
FX_PLUGIN_IDENTIFIER(Iwa_BloomFx, "iwa_BloomFx")
\ No newline at end of file
diff --git a/toonz/sources/stdfx/iwa_bloomfx.h b/toonz/sources/stdfx/iwa_bloomfx.h
index bc5f274..8153898 100644
--- a/toonz/sources/stdfx/iwa_bloomfx.h
+++ b/toonz/sources/stdfx/iwa_bloomfx.h
@@ -19,22 +19,32 @@ value
class Iwa_BloomFx : public TStandardRasterFx {
FX_PLUGIN_DECLARATION(Iwa_BloomFx)
+
+ enum AlphaMode { NoAlpha = 0, Light, LightAndSource };
+
protected:
TRasterFxPort m_source;
TDoubleParamP m_gamma;
+ TBoolParamP m_auto_gain;
+ TDoubleParamP m_gain_adjust;
TDoubleParamP m_gain;
+ TDoubleParamP m_decay;
TDoubleParamP m_size;
- TBoolParamP m_alpha_rendering;
+
+ TIntEnumParamP m_alpha_mode; // no alpha / light / light and source
+ TBoolParamP m_alpha_rendering; // obsolete
double getSizePixelAmount(const double val, const TAffine affine);
template
- void setSourceTileToMat(const RASTER ras, cv::Mat &ingMat,
+ void setSourceTileToMat(const RASTER ras, cv::Mat &imgMat,
const double gamma);
template
- void setMatToOutput(const RASTER ras, const RASTER srcRas, cv::Mat &ingMat,
+ void setMatToOutput(const RASTER ras, const RASTER srcRas, cv::Mat &imgMat,
const double gamma, const double gain,
- const bool withAlpha, const int margin);
+ const AlphaMode alphaMode, const int margin);
+
+ double computeAutoGain(cv::Mat &imgMat);
public:
Iwa_BloomFx();
@@ -44,6 +54,7 @@ public:
const TRenderSettings &info) override;
bool canHandle(const TRenderSettings &info, double frame) override;
void getParamUIs(TParamUIConcept *&concepts, int &length) override;
+ void onObsoleteParamLoaded(const std::string ¶mName) override;
};
#endif
\ No newline at end of file
diff --git a/toonz/sources/toonzqt/doublefield.cpp b/toonz/sources/toonzqt/doublefield.cpp
index dad7f9b..643f18a 100644
--- a/toonz/sources/toonzqt/doublefield.cpp
+++ b/toonz/sources/toonzqt/doublefield.cpp
@@ -324,7 +324,7 @@ DoubleLineEdit::DoubleLineEdit(QWidget *parent, double value)
: DoubleValueLineEdit(parent) {
m_validator =
new QDoubleValidator(-(std::numeric_limits::max)(),
- (std::numeric_limits::max)(), 8, this);
+ (std::numeric_limits::max)(), 5, this);
setValidator(m_validator);
setValue(value);
diff --git a/toonz/sources/toonzqt/fxsettings.cpp b/toonz/sources/toonzqt/fxsettings.cpp
index d8026b9..d136253 100644
--- a/toonz/sources/toonzqt/fxsettings.cpp
+++ b/toonz/sources/toonzqt/fxsettings.cpp
@@ -151,7 +151,7 @@ void ParamsPage::setPageField(TIStream &is, const TFxP &fx, bool isVertical) {
if (tagName == "control") {
/*--- 設定ファイルからインタフェースの桁数を決める (PairSliderのみ実装。)
* ---*/
- int decimals = 0;
+ int decimals = -1;
std::string decimalsStr = is.getTagAttribute("decimals");
if (decimalsStr != "") {
decimals = QString::fromStdString(decimalsStr).toInt();
@@ -168,7 +168,7 @@ void ParamsPage::setPageField(TIStream &is, const TFxP &fx, bool isVertical) {
QString::fromStdWString(TStringTable::translate(paramName));
ParamField *field = ParamField::create(this, str, param);
if (field) {
- if (decimals) field->setPrecision(decimals);
+ if (decimals >= 0) field->setPrecision(decimals);
m_fields.push_back(field);
/*-- hboxタグに挟まれているとき --*/
if (isVertical == false) {
@@ -919,7 +919,7 @@ void ParamsPageSet::createPage(TIStream &is, const TFxP &fx, int index) {
std::string tagName;
if (!is.matchTag(tagName) || tagName != "page")
throw TException("expected ");
- std::string pageName = is.getTagAttribute("name");
+ std::string pageName = is.getTagAttribute("name");
if (pageName == "") pageName = "page";
ParamsPage *paramsPage = new ParamsPage(this, m_parent);
@@ -1197,7 +1197,7 @@ FxSettings::FxSettings(QWidget *parent, const TPixel32 &checkCol1,
bool ret = true;
ret = ret && connect(m_paramViewer, SIGNAL(currentFxParamChanged()),
SLOT(updateViewer()));
- ret = ret &&
+ ret = ret &&
connect(m_viewer, SIGNAL(pointPositionChanged(int, const TPointD &)),
SLOT(onPointChanged(int, const TPointD &)));
ret = ret && connect(m_paramViewer, SIGNAL(preferredSizeChanged(QSize)), this,
@@ -1345,10 +1345,10 @@ void FxSettings::setFx(const TFxP ¤tFx, const TFxP &actualFx) {
TFxUtil::setKeyframe(currentFxWithoutCamera, m_frameHandle->getFrameIndex(),
actualFx, m_frameHandle->getFrameIndex());
- ToonzScene *scene = 0;
+ ToonzScene *scene = 0;
if (m_sceneHandle) scene = m_sceneHandle->getScene();
- int frameIndex = 0;
+ int frameIndex = 0;
if (m_frameHandle) frameIndex = m_frameHandle->getFrameIndex();
m_paramViewer->setFx(currentFxWithoutCamera, actualFx, frameIndex, scene);
@@ -1408,7 +1408,7 @@ void FxSettings::setCurrentFx() {
if (TZeraryColumnFx *zfx = dynamic_cast(fx.getPointer()))
fx = zfx->getZeraryFx();
else
- hasEmptyInput = hasEmptyInputPort(fx);
+ hasEmptyInput = hasEmptyInputPort(fx);
int frame = m_frameHandle->getFrame();
ToonzScene *scene = m_sceneHandle->getScene();
actualFx = fx;
diff --git a/toonz/sources/toonzqt/paramfield.cpp b/toonz/sources/toonzqt/paramfield.cpp
index 736c375..f46ae16 100644
--- a/toonz/sources/toonzqt/paramfield.cpp
+++ b/toonz/sources/toonzqt/paramfield.cpp
@@ -846,6 +846,16 @@ void MeasuredDoubleParamField::onChange(bool dragging) {
void MeasuredDoubleParamField::onKeyToggled() { onKeyToggle(); }
+//-----------------------------------------------------------------------------
+
+void MeasuredDoubleParamField::setPrecision(int precision) {
+ double min, max;
+ m_measuredDoubleField->getRange(min, max);
+ m_measuredDoubleField->setDecimals(precision);
+ // update slider
+ m_measuredDoubleField->setRange(min, max);
+}
+
//=============================================================================
// MeasuredRangeParamField
//-----------------------------------------------------------------------------