#include "iwa_spingradientfx.h"
#include "trop.h"
#include "tparamuiconcept.h"
#include "tspectrumparam.h"
#include "gradients.h"
#include <QPolygonF>
#include <array>
#include <algorithm>
//------------------------------------------------------------
Iwa_SpinGradientFx::Iwa_SpinGradientFx()
: m_center(TPointD(0.0, 0.0))
, m_startAngle(0.0)
, m_endAngle(0.0)
, m_startColor(TPixel32::Black)
, m_endColor(TPixel32::White)
, m_curveType(new TIntEnumParam()) {
m_center->getX()->setMeasureName("fxLength");
m_center->getY()->setMeasureName("fxLength");
bindParam(this, "center", m_center);
m_startAngle->setValueRange(-360, 720);
m_endAngle->setValueRange(-360, 720);
bindParam(this, "startAngle", m_startAngle);
bindParam(this, "endAngle", m_endAngle);
m_curveType->addItem(EaseInOut, "Ease In-Out");
m_curveType->addItem(Linear, "Linear");
m_curveType->addItem(EaseIn, "Ease In");
m_curveType->addItem(EaseOut, "Ease Out");
m_curveType->setDefaultValue(Linear);
m_curveType->setValue(Linear);
bindParam(this, "curveType", m_curveType);
bindParam(this, "startColor", m_startColor);
bindParam(this, "endColor", m_endColor);
enableComputeInFloat(true);
}
//------------------------------------------------------------
bool Iwa_SpinGradientFx::doGetBBox(double frame, TRectD &bBox,
const TRenderSettings &ri) {
bBox = TConsts::infiniteRectD;
return true;
}
//------------------------------------------------------------
namespace {
template <typename RASTER, typename PIXEL>
void doSpinGradientT(RASTER ras, TDimensionI dim, TPointD centerPos,
double startAngle, double endAngle,
const TSpectrumT<PIXEL> &spectrum,
GradientCurveType type) {
auto getFactor = [&](double angle) {
double p = angle - startAngle;
if (p < 0) p += 2.0 * M_PI;
double range = endAngle - startAngle;
if (range <= 0) range += 2.0 * M_PI;
double t;
if (range >= p)
t = p / range;
else if (M_PI + range / 2.0 > p)
t = 1.0;
else
t = 0.0;
double factor;
switch (type) {
case Linear:
factor = t;
break;
case EaseIn:
factor = t * t;
break;
case EaseOut:
factor = 1.0 - (1.0 - t) * (1.0 - t);
break;
case EaseInOut:
default:
factor = (-2 * t + 3) * (t * t);
break;
}
return factor;
};
ras->lock();
for (int j = 0; j < ras->getLy(); j++) {
PIXEL *pix = ras->pixels(j);
PIXEL *endPix = pix + ras->getLx();
double dy = (double)j - centerPos.y;
double dx = -centerPos.x;
while (pix < endPix) {
double angle = std::atan2(dy, dx);
double factor = getFactor(angle);
*pix++ = spectrum.getPremultipliedValue(factor);
dx += 1.0;
}
}
ras->unlock();
}
} // namespace
//------------------------------------------------------------
void Iwa_SpinGradientFx::doCompute(TTile &tile, double frame,
const TRenderSettings &ri) {
if (!((TRaster32P)tile.getRaster()) && !((TRaster64P)tile.getRaster()) &&
!((TRasterFP)tile.getRaster())) {
throw TRopException("unsupported input pixel type");
}
// convert shape position to render region coordinate
TAffine aff = ri.m_affine;
TDimensionI dimOut(tile.getRaster()->getLx(), tile.getRaster()->getLy());
TPointD dimOffset((float)dimOut.lx / 2.0f, (float)dimOut.ly / 2.0f);
TPointD centerPos = aff * m_center->getValue(frame) -
(tile.m_pos + tile.getRaster()->getCenterD()) + dimOffset;
std::vector<TSpectrum::ColorKey> colors = {
TSpectrum::ColorKey(0, m_startColor->getValue(frame)),
TSpectrum::ColorKey(1, m_endColor->getValue(frame))};
TSpectrumParamP m_colors = TSpectrumParamP(colors);
auto conv2RadianAndClamp = [](double angle) {
double ret = angle * M_PI / 180.0;
while (ret < -M_PI) {
ret += 2.0 * M_PI;
}
while (ret >= M_PI) {
ret -= 2.0 * M_PI;
}
return ret;
};
double startAngle = conv2RadianAndClamp(m_startAngle->getValue(frame));
double endAngle = conv2RadianAndClamp(m_endAngle->getValue(frame));
tile.getRaster()->clear();
TRaster32P outRas32 = (TRaster32P)tile.getRaster();
TRaster64P outRas64 = (TRaster64P)tile.getRaster();
TRasterFP outRasF = (TRasterFP)tile.getRaster();
if (outRas32)
doSpinGradientT<TRaster32P, TPixel32>(
outRas32, dimOut, centerPos, startAngle, endAngle,
m_colors->getValue(frame), (GradientCurveType)m_curveType->getValue());
else if (outRas64)
doSpinGradientT<TRaster64P, TPixel64>(
outRas64, dimOut, centerPos, startAngle, endAngle,
m_colors->getValue64(frame),
(GradientCurveType)m_curveType->getValue());
else if (outRasF)
doSpinGradientT<TRasterFP, TPixelF>(
outRasF, dimOut, centerPos, startAngle, endAngle,
m_colors->getValueF(frame), (GradientCurveType)m_curveType->getValue());
}
//------------------------------------------------------------
void Iwa_SpinGradientFx::getParamUIs(TParamUIConcept *&concepts, int &length) {
concepts = new TParamUIConcept[length = 2];
concepts[0].m_type = TParamUIConcept::ANGLE_2;
concepts[0].m_label = "Angle";
concepts[0].m_params.push_back(m_startAngle);
concepts[0].m_params.push_back(m_endAngle);
concepts[0].m_params.push_back(m_center);
concepts[1].m_type = TParamUIConcept::POINT;
concepts[1].m_label = "Center";
concepts[1].m_params.push_back(m_center);
}
//------------------------------------------------------------
FX_PLUGIN_IDENTIFIER(Iwa_SpinGradientFx, "iwa_SpinGradientFx");