diff --git a/stuff/config/current.txt b/stuff/config/current.txt index 7aa6923..cb1f02a 100644 --- a/stuff/config/current.txt +++ b/stuff/config/current.txt @@ -1294,6 +1294,16 @@ "STD_iwa_SpinGradientFx.endAngle" "End Angle" "STD_iwa_SpinGradientFx.endColor" "End Color" + "STD_iwa_LinearGradientFx" "Linear Gradient" + "STD_iwa_LinearGradientFx.curveType" "Type" + "STD_iwa_LinearGradientFx.startPoint" "Start Point" + "STD_iwa_LinearGradientFx.startColor" "Start Color" + "STD_iwa_LinearGradientFx.endPoint" "End Point" + "STD_iwa_LinearGradientFx.endColor" "End Color" + "STD_iwa_LinearGradientFx.wave_amplitude" "Amplitude" + "STD_iwa_LinearGradientFx.wave_frequency" "Frequency" + "STD_iwa_LinearGradientFx.wave_phase" "Phase" + STD_iwa_TiledParticlesFx "Tiled Particles Iwa" diff --git a/stuff/profiles/layouts/fxs/STD_iwa_LinearGradientFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_LinearGradientFx.xml new file mode 100644 index 0000000..8e0d915 --- /dev/null +++ b/stuff/profiles/layouts/fxs/STD_iwa_LinearGradientFx.xml @@ -0,0 +1,14 @@ + + + startPoint + endPoint + startColor + endColor + startColor endColor + curveType + + wave_amplitude + wave_frequency + wave_phase + + diff --git a/stuff/profiles/layouts/fxs/STD_linearGradientFx.xml b/stuff/profiles/layouts/fxs/STD_linearGradientFx.xml index de531e5..7c48ba7 100644 --- a/stuff/profiles/layouts/fxs/STD_linearGradientFx.xml +++ b/stuff/profiles/layouts/fxs/STD_linearGradientFx.xml @@ -1,5 +1,5 @@ - + period color1 color2 diff --git a/stuff/profiles/layouts/fxs/fxs.lst b/stuff/profiles/layouts/fxs/fxs.lst index f2d13c3..dca20c1 100644 --- a/stuff/profiles/layouts/fxs/fxs.lst +++ b/stuff/profiles/layouts/fxs/fxs.lst @@ -38,7 +38,7 @@ STD_diamondGradientFx STD_fourPointsGradientFx - STD_linearGradientFx + STD_iwa_LinearGradientFx STD_multiLinearGradientFx STD_multiRadialGradientFx STD_radialGradientFx diff --git a/toonz/sources/include/tparamuiconcept.h b/toonz/sources/include/tparamuiconcept.h index 8a62c37..b72a278 100644 --- a/toonz/sources/include/tparamuiconcept.h +++ b/toonz/sources/include/tparamuiconcept.h @@ -61,8 +61,10 @@ public: RECT, // A Rect, with width, height and center. { [2 // TDoubleParamP], TPointParamP } - DIAMOND, // A diagonally laid square. { - // [TDoubleParamP] } + DIAMOND, // A diagonally laid square. { + // [TDoubleParamP] } + LINEAR_RANGE, // A band-like range between two points. + // { [2 TPointParamP] } TYPESCOUNT }; diff --git a/toonz/sources/stdfx/CMakeLists.txt b/toonz/sources/stdfx/CMakeLists.txt index e871986..52449bd 100644 --- a/toonz/sources/stdfx/CMakeLists.txt +++ b/toonz/sources/stdfx/CMakeLists.txt @@ -78,6 +78,7 @@ set(HEADERS iwa_textfx.h iwa_corridorgradientfx.h iwa_spingradientfx.h + iwa_lineargradientfx.h ) set(SOURCES @@ -262,6 +263,7 @@ set(SOURCES iwa_textfx.cpp iwa_corridorgradientfx.cpp iwa_spingradientfx.cpp + iwa_lineargradientfx.cpp ) set(OBJCSOURCES diff --git a/toonz/sources/stdfx/iwa_lineargradientfx.cpp b/toonz/sources/stdfx/iwa_lineargradientfx.cpp new file mode 100644 index 0000000..173aa89 --- /dev/null +++ b/toonz/sources/stdfx/iwa_lineargradientfx.cpp @@ -0,0 +1,178 @@ +#include "iwa_lineargradientfx.h" + +#include "tspectrumparam.h" +#include "gradients.h" +#include "tparamuiconcept.h" +#include "traster.h" + +//------------------------------------------------------------ + +Iwa_LinearGradientFx::Iwa_LinearGradientFx() + : m_startPoint(TPointD(-50.0, 0.0)) + , m_endPoint(TPointD(50.0, 0.0)) + , m_startColor(TPixel32::Black) + , m_endColor(TPixel32::White) + , m_curveType(new TIntEnumParam(EaseInOut, "Ease In-Out")) + , m_wave_amplitude(0.0) + , m_wave_freq(0.0) + , m_wave_phase(0.0) { + m_startPoint->getX()->setMeasureName("fxLength"); + m_startPoint->getY()->setMeasureName("fxLength"); + m_endPoint->getX()->setMeasureName("fxLength"); + m_endPoint->getY()->setMeasureName("fxLength"); + bindParam(this, "startPoint", m_startPoint); + bindParam(this, "endPoint", m_endPoint); + + m_curveType->addItem(Linear, "Linear"); + m_curveType->addItem(EaseIn, "Ease In"); + m_curveType->addItem(EaseOut, "Ease Out"); + bindParam(this, "curveType", m_curveType); + + m_wave_amplitude->setValueRange(0, std::numeric_limits::max()); + m_wave_amplitude->setMeasureName("fxLength"); + bindParam(this, "wave_amplitude", m_wave_amplitude); + bindParam(this, "wave_frequency", m_wave_freq); + bindParam(this, "wave_phase", m_wave_phase); + + bindParam(this, "startColor", m_startColor); + bindParam(this, "endColor", m_endColor); +} + +//------------------------------------------------------------ + +bool Iwa_LinearGradientFx::doGetBBox(double frame, TRectD &bBox, + const TRenderSettings &ri) { + bBox = TConsts::infiniteRectD; + return true; +} + +//------------------------------------------------------------ + +namespace { +template +void doLinearGradientT(RASTER ras, TDimensionI dim, TPointD startPos, + TPointD endPos, const TSpectrumT &spectrum, + GradientCurveType type, double w_amplitude, + double w_freq, double w_phase, const TAffine &affInv) { + auto getFactor = [&](double t) { + if (t > 1.0) + t = 1.0; + else if (t < 0.0) + 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; + }; + startPos = affInv * startPos; + endPos = affInv * endPos; + TPointD seVec = endPos - startPos; + + if (seVec == TPointD()) { + ras->fill(spectrum.getPremultipliedValue(0.0)); + return; + } + + TPointD posTrasf = -startPos; + double seVecLen2 = seVec.x * seVec.x + seVec.y * seVec.y; + double seVecLen = sqrt(seVecLen2); + double amplitude = w_amplitude / seVecLen; + TPointD auxVec(-seVec.y / seVecLen, seVec.x / seVecLen); + + ras->lock(); + for (int j = 0; j < ras->getLy(); j++) { + TPointD posAux = posTrasf; + + PIXEL *pix = ras->pixels(j); + PIXEL *endPix = pix + ras->getLx(); + + while (pix < endPix) { + double t = (seVec.x * posAux.x + seVec.y * posAux.y) / seVecLen2; + if (amplitude) { + double distance = posAux.x * auxVec.x + posAux.y * auxVec.y; + t += amplitude * sin(w_freq * distance + w_phase); + } + double factor = getFactor(t); + *pix++ = spectrum.getPremultipliedValue(factor); + + posAux.x += affInv.a11; + posAux.y += affInv.a21; + } + posTrasf.x += affInv.a12; + posTrasf.y += affInv.a22; + } + ras->unlock(); +} +} // namespace + +//------------------------------------------------------------ + +void Iwa_LinearGradientFx::doCompute(TTile &tile, double frame, + const TRenderSettings &ri) { + if (!((TRaster32P)tile.getRaster()) && !((TRaster64P)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 startPos = aff * m_startPoint->getValue(frame) - + (tile.m_pos + tile.getRaster()->getCenterD()) + dimOffset; + TPointD endPos = aff * m_endPoint->getValue(frame) - + (tile.m_pos + tile.getRaster()->getCenterD()) + dimOffset; + + double w_amplitude = m_wave_amplitude->getValue(frame) / ri.m_shrinkX; + double w_freq = m_wave_freq->getValue(frame) * ri.m_shrinkX; + double w_phase = m_wave_phase->getValue(frame); + w_freq *= 0.01 * M_PI_180; + + std::vector colors = { + TSpectrum::ColorKey(0, m_startColor->getValue(frame)), + TSpectrum::ColorKey(1, m_endColor->getValue(frame))}; + TSpectrumParamP m_colors = TSpectrumParamP(colors); + + tile.getRaster()->clear(); + TRaster32P outRas32 = (TRaster32P)tile.getRaster(); + TRaster64P outRas64 = (TRaster64P)tile.getRaster(); + if (outRas32) + doLinearGradientT( + outRas32, dimOut, startPos, endPos, m_colors->getValue(frame), + (GradientCurveType)m_curveType->getValue(), w_amplitude, w_freq, + w_phase, aff.inv()); + else if (outRas64) + doLinearGradientT( + outRas64, dimOut, startPos, endPos, m_colors->getValue64(frame), + (GradientCurveType)m_curveType->getValue(), w_amplitude, w_freq, + w_phase, aff.inv()); +} + +//------------------------------------------------------------ + +void Iwa_LinearGradientFx::getParamUIs(TParamUIConcept *&concepts, + int &length) { + concepts = new TParamUIConcept[length = 1]; + + concepts[0].m_type = TParamUIConcept::LINEAR_RANGE; + concepts[0].m_label = ""; + concepts[0].m_params.push_back(m_startPoint); + concepts[0].m_params.push_back(m_endPoint); +} + +//------------------------------------------------------------ + +FX_PLUGIN_IDENTIFIER(Iwa_LinearGradientFx, "iwa_LinearGradientFx"); diff --git a/toonz/sources/stdfx/iwa_lineargradientfx.h b/toonz/sources/stdfx/iwa_lineargradientfx.h new file mode 100644 index 0000000..88bfe33 --- /dev/null +++ b/toonz/sources/stdfx/iwa_lineargradientfx.h @@ -0,0 +1,32 @@ +#pragma once +#ifndef IWA_LINEARGRADIENTFX_H +#define IWA_LINEARGRADIENTFX_H + +#include "tfxparam.h" +#include "stdfx.h" +#include "tparamset.h" + +class Iwa_LinearGradientFx final : public TStandardZeraryFx { + FX_PLUGIN_DECLARATION(Iwa_LinearGradientFx) + + TIntEnumParamP m_curveType; + TPointParamP m_startPoint, m_endPoint; + TPixelParamP m_startColor, m_endColor; + + TDoubleParamP m_wave_amplitude; + TDoubleParamP m_wave_freq; + TDoubleParamP m_wave_phase; + +public: + Iwa_LinearGradientFx(); + + bool canHandle(const TRenderSettings &info, double frame) override { + return true; + } + bool doGetBBox(double frame, TRectD &bBox, + const TRenderSettings &ri) override; + void doCompute(TTile &tile, double frame, const TRenderSettings &ri) override; + void getParamUIs(TParamUIConcept *&concepts, int &length) override; +}; + +#endif \ No newline at end of file diff --git a/toonz/sources/stdfx/stdfx.cpp b/toonz/sources/stdfx/stdfx.cpp index 2f11f6c..1183754 100644 --- a/toonz/sources/stdfx/stdfx.cpp +++ b/toonz/sources/stdfx/stdfx.cpp @@ -236,6 +236,11 @@ public: } }; +// From V1.4 LinearGradientFx becomes obsolete and was replaced by +// Iwa_LinearGradientFx which has more flexibility. (iwa_lineargradientfx.cpp) +// This code is kept in order to load the fx made with older OT versions. +// Nov 14, 2019 + class LinearGradientFx final : public TStandardZeraryFx { FX_PLUGIN_DECLARATION(LinearGradientFx) TDoubleParamP m_period; diff --git a/toonz/sources/tnztools/edittoolgadgets.cpp b/toonz/sources/tnztools/edittoolgadgets.cpp index 2cd9d93..ffad94e 100644 --- a/toonz/sources/tnztools/edittoolgadgets.cpp +++ b/toonz/sources/tnztools/edittoolgadgets.cpp @@ -1342,6 +1342,192 @@ void QuadFxGadget::leftButtonUp(const TPointD &pos, const TMouseEvent &) { m_handle = None; } +//============================================================================= + +class LinearRangeFxGadget final : public FxGadget { + TPointParamP m_start, m_end; + + enum HANDLE { Body = 0, Start, End, None } m_handle = None; + + TPointD m_clickedPos; + TPointD m_targetPos, m_anotherPos; + +public: + LinearRangeFxGadget(FxGadgetController *controller, + const TPointParamP &startPoint, + const TPointParamP &endPoint); + + void draw(bool picking) override; + + void leftButtonDown(const TPointD &pos, const TMouseEvent &) override; + void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override; + void leftButtonUp(const TPointD &pos, const TMouseEvent &) override; +}; + +//--------------------------------------------------------------------------- + +LinearRangeFxGadget::LinearRangeFxGadget(FxGadgetController *controller, + const TPointParamP &startPoint, + const TPointParamP &endPoint) + : FxGadget(controller, 3), m_start(startPoint), m_end(endPoint) { + addParam(startPoint->getX()); + addParam(startPoint->getY()); + addParam(endPoint->getX()); + addParam(endPoint->getY()); +} + +//--------------------------------------------------------------------------- + +void LinearRangeFxGadget::draw(bool picking) { + auto setColorById = [&](int id) { + if (isSelected(id)) + glColor3dv(m_selectedColor); + else + glColor3d(0, 0, 1); + }; + + auto drawPoint = [&]() { + double r = getPixelSize() * 3; + double d = getPixelSize() * 6; + glBegin(GL_LINES); + glVertex2d(-d, 0); + glVertex2d(-r, 0); + glVertex2d(d, 0); + glVertex2d(r, 0); + glVertex2d(0, -d); + glVertex2d(0, -r); + glVertex2d(0, d); + glVertex2d(0, r); + glEnd(); + tglDrawRect(-r, -r, r, r); + }; + + setPixelSize(); + double r = getPixelSize() * 200; + double a = getPixelSize() * 5; + + TPointD start = getValue(m_start); + TPointD end = getValue(m_end); + + glPushMatrix(); + + if (start != end) { + // draw lines perpendicular to the line between ends + double angle = std::atan2(start.x - end.x, end.y - start.y) * M_180_PI; + // start + setColorById(Start); + glPushMatrix(); + glTranslated(start.x, start.y, 0); + glRotated(angle, 0, 0, 1); + if (m_handle == Start) glScaled(5.0, 1.0, 1.0); + glBegin(GL_LINES); + glVertex2d(-r, 0); + glVertex2d(r, 0); + glEnd(); + glPopMatrix(); + // end + setColorById(End); + glPushMatrix(); + glTranslated(end.x, end.y, 0); + glRotated(angle, 0, 0, 1); + if (m_handle == End) glScaled(5.0, 1.0, 1.0); + glBegin(GL_LINE_STRIP); + glVertex2d(-r, 0); + glVertex2d(r, 0); + glEnd(); + glPopMatrix(); + + // line body + setColorById(Body); + glPushName(getId() + Body); + glBegin(GL_LINES); + glVertex2d(start.x, start.y); + glVertex2d(end.x, end.y); + glEnd(); + // small dash at the center + glPushMatrix(); + glTranslated((start.x + end.x) / 2.0, (start.y + end.y) / 2.0, 0); + glRotated(angle, 0, 0, 1); + glBegin(GL_LINES); + glVertex2d(-a, 0); + glVertex2d(a, 0); + glEnd(); + glPopMatrix(); + glPopName(); + } + + // start point + setColorById(Start); + glPushName(getId() + Start); + glPushMatrix(); + glTranslated(start.x, start.y, 0); + drawPoint(); + glPopMatrix(); + glPopName(); + drawTooltip(start + TPointD(7, 3) * getPixelSize(), "Start"); + + // end point + setColorById(End); + glPushName(getId() + End); + glPushMatrix(); + glTranslated(end.x, end.y, 0); + drawPoint(); + glPopMatrix(); + glPopName(); + drawTooltip(end + TPointD(7, 3) * getPixelSize(), "End"); + + glPopMatrix(); +} + +//--------------------------------------------------------------------------- + +void LinearRangeFxGadget::leftButtonDown(const TPointD &pos, + const TMouseEvent &) { + m_handle = (HANDLE)m_selected; + if (m_handle == None) return; + m_clickedPos = pos; + m_targetPos = (m_handle == Start || m_handle == Body) ? getValue(m_start) + : getValue(m_end); + m_anotherPos = (m_handle == Start || m_handle == Body) ? getValue(m_end) + : getValue(m_start); +} + +//--------------------------------------------------------------------------- + +void LinearRangeFxGadget::leftButtonDrag(const TPointD &pos, + const TMouseEvent &e) { + if (m_handle == None) return; + TPointD d = pos - m_clickedPos; + + if (m_handle == Body) { + setValue(m_start, m_targetPos + d); + setValue(m_end, m_anotherPos + d); + return; + } + + TPointParamP target = (m_handle == Start) ? m_start : m_end; + + if (m_targetPos != m_anotherPos && e.isShiftPressed()) { + TPointD vecA = m_targetPos - m_anotherPos; + TPointD vecB = m_targetPos + d - m_anotherPos; + double ratio = std::min(vecB.x / vecA.x, vecB.y / vecA.y); + d = vecA * (ratio - 1.0); + } + + setValue(target, m_targetPos + d); + + if (e.isCtrlPressed()) { + TPointParamP another = (m_handle == Start) ? m_end : m_start; + setValue(another, m_anotherPos - d); + } +} + +//--------------------------------------------------------------------------- + +void LinearRangeFxGadget::leftButtonUp(const TPointD &pos, + const TMouseEvent &) { + m_handle = None; +} //************************************************************************************* // FxGadgetController implementation //************************************************************************************* @@ -1519,6 +1705,13 @@ FxGadget *FxGadgetController::allocateGadget(const TParamUIConcept &uiConcept) { gadget = new DiamondFxGadget(this, uiConcept.m_params[0]); break; } + + case TParamUIConcept::LINEAR_RANGE: { + assert(uiConcept.m_params.size() == 2); + gadget = new LinearRangeFxGadget(this, uiConcept.m_params[0], + uiConcept.m_params[1]); + break; + } } if (gadget) gadget->setLabel(uiConcept.m_label);