tahoma2d/toonz/sources/stdfx/blurfx.cpp

182 lines
5.9 KiB
C++
Raw Normal View History

2016-03-19 06:57:51 +13:00
#include "texception.h"
#include "tfxparam.h"
#include "trop.h"
#include "stdfx.h"
#include "trasterfx.h"
//-------------------------------------------------------------------
class BlurFx final : public TStandardRasterFx {
2016-06-15 18:43:10 +12:00
FX_PLUGIN_DECLARATION(BlurFx)
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TRasterFxPort m_input;
TDoubleParamP m_value;
TBoolParamP m_useSSE;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
BlurFx() : m_value(20), m_useSSE(true) {
m_value->setMeasureName("fxLength");
bindParam(this, "value", m_value);
bindParam(this, "useSSE", m_useSSE, true);
addInputPort("Source", m_input);
m_value->setValueRange(0, std::numeric_limits<double>::max());
}
~BlurFx(){};
2016-06-20 14:23:05 +12:00
bool doGetBBox(double frame, TRectD &bBox,
const TRenderSettings &info) override {
2016-06-15 18:43:10 +12:00
if (m_input.isConnected()) {
bool ret = m_input->doGetBBox(frame, bBox, info);
double blur = fabs(m_value->getValue(frame));
int brad = tceil(blur);
bBox = bBox.enlarge(brad);
return ret;
} else {
bBox = TRectD();
return false;
}
}
void enlarge(const TRectD &bbox, TRectD &requestedRect, int blur);
void transform(double frame, int port, const TRectD &rectOnOutput,
const TRenderSettings &infoOnOutput, TRectD &rectOnInput,
2016-06-19 20:06:29 +12:00
TRenderSettings &infoOnInput) override;
2016-06-15 18:43:10 +12:00
2016-06-19 20:06:29 +12:00
void doCompute(TTile &tile, double frame, const TRenderSettings &) override;
2016-06-15 18:43:10 +12:00
int getMemoryRequirement(const TRectD &rect, double frame,
2016-06-19 20:06:29 +12:00
const TRenderSettings &info) override;
2016-06-15 18:43:10 +12:00
2016-06-19 20:06:29 +12:00
bool canHandle(const TRenderSettings &info, double frame) override {
2016-06-15 18:43:10 +12:00
if (m_value->getValue(frame) == 0) return true;
return (isAlmostIsotropic(info.m_affine));
}
2016-03-19 06:57:51 +13:00
};
FX_PLUGIN_IDENTIFIER(BlurFx, "blurFx")
//-------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
//! Calculates the geometry we need for this node computation, given
//! the known input data (bbox), the requested output (requestedRect) and the
//! blur factor.
void BlurFx::enlarge(const TRectD &bbox, TRectD &requestedRect, int blur) {
if (bbox.isEmpty() || requestedRect.isEmpty()) {
requestedRect.empty();
return;
}
// We are to find out the geometry that is useful for the fx computation.
// There are some rules to follow:
// a) First, the interesting output we can generate is bounded by both
// the requestedRect and the blurred bbox (i.e. enlarged by the blur
// radius).
// b) Pixels contributing to any output are necessarily part of bbox - and
// only
// those which are blurrable into the requestedRect are useful to us
// (i.e. pixels contained in its enlargement by the blur radius).
TRectD enlargedBBox(bbox.enlarge(blur));
TRectD enlargedOut(requestedRect.enlarge(blur));
TPointD originalP00(requestedRect.getP00());
requestedRect = (enlargedOut * bbox) + (enlargedBBox * requestedRect);
// Finally, make sure that the result is coherent with the original P00
requestedRect -= originalP00;
requestedRect.x0 = tfloor(requestedRect.x0);
requestedRect.y0 = tfloor(requestedRect.y0);
requestedRect.x1 = tceil(requestedRect.x1);
requestedRect.y1 = tceil(requestedRect.y1);
requestedRect += originalP00;
2016-03-19 06:57:51 +13:00
}
//-------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void BlurFx::transform(double frame, int port, const TRectD &rectOnOutput,
const TRenderSettings &infoOnOutput, TRectD &rectOnInput,
TRenderSettings &infoOnInput) {
infoOnInput = infoOnOutput;
rectOnInput = rectOnOutput;
double blur =
fabs(m_value->getValue(frame) * sqrt(fabs(infoOnOutput.m_affine.det())));
if (blur == 0) {
rectOnInput = rectOnOutput;
return;
}
int brad = tceil(blur);
TRectD bbox;
m_input->getBBox(frame, bbox, infoOnInput);
enlarge(bbox, rectOnInput, brad);
2016-03-19 06:57:51 +13:00
}
//-------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
int BlurFx::getMemoryRequirement(const TRectD &rect, double frame,
const TRenderSettings &info) {
double blurValue =
fabs(m_value->getValue(frame) * sqrt(fabs(info.m_affine.det())));
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (blurValue == 0.0) return 0;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
int brad = tceil(blurValue);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Trop::blur is quite inefficient at the moment - it has to allocate a whole
// raster of the same size of the input/output made of FLOAT QUADRUPLES...!
return TRasterFx::memorySize(rect.enlarge(brad), sizeof(float) << 5);
2016-03-19 06:57:51 +13:00
}
//-------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void BlurFx::doCompute(TTile &tile, double frame,
const TRenderSettings &renderSettings) {
if (!m_input.isConnected()) return;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
double shrink = 0.5 * (renderSettings.m_shrinkX + renderSettings.m_shrinkY);
// Note: shrink is obsolete. It should be always = 1
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
double blurValue = fabs(m_value->getValue(frame) *
sqrt(fabs(renderSettings.m_affine.det())) / shrink);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (blurValue == 0) {
// No blur will be done. The underlying fx may pass by.
m_input->compute(tile, frame, renderSettings);
return;
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
int brad = tceil(blurValue);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Get the requested tile's geometry
TRectD rectIn, rectOut;
rectOut = TRectD(tile.m_pos, TDimensionD(tile.getRaster()->getLx(),
tile.getRaster()->getLy()));
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Retrieve the input interesting geometry - and ensure that something
// actually has
// to be computed
if (!m_input->getBBox(frame, rectIn, renderSettings) || rectOut.isEmpty())
return;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
enlarge(rectIn, rectOut, brad);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (rectOut.isEmpty()) return;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Finally, allocate and compute the blur argument
TTile tileIn;
m_input->allocateAndCompute(tileIn, rectOut.getP00(),
TDimension(rectOut.getLx(), rectOut.getLy()),
tile.getRaster(), frame, renderSettings);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TPointD displacement(rectOut.getP00() - tile.m_pos);
TRop::blur(tile.getRaster(), tileIn.getRaster(), blurValue, displacement.x,
displacement.y, false);
2016-03-19 06:57:51 +13:00
}