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