| |
| |
| #include "texception.h" |
| #include "tfxparam.h" |
| #include "stdfx.h" |
| |
| #include "tparamset.h" |
| |
| static void OLDRGB2HSV(double r, double g, double b, double *h, double *s, |
| double *v) { |
| double max, min; |
| double delta; |
| |
| max = std::max({r, g, b}); |
| min = std::min({r, g, b}); |
| |
| *v = max; |
| |
| if (max != 0) |
| *s = (max - min) / max; |
| else |
| *s = 0; |
| |
| if (*s == 0) |
| *h = 0; |
| else { |
| delta = max - min; |
| |
| if (r == max) |
| *h = (g - b) / delta; |
| else if (g == max) |
| *h = 2 + (b - r) / delta; |
| else if (b == max) |
| *h = 4 + (r - g) / delta; |
| *h = *h * 60; |
| if (*h < 0) *h += 360; |
| } |
| } |
| |
| static void OLDHSV2RGB(double hue, double sat, double value, double *red, |
| double *green, double *blue) { |
| int i; |
| double p, q, t, f; |
| |
| |
| |
| if (hue > 360) hue -= 360; |
| if (hue < 0) hue += 360; |
| if (sat < 0) sat = 0; |
| if (sat > 1) sat = 1; |
| if (value < 0) value = 0; |
| if (value > 1) value = 1; |
| if (sat == 0) { |
| *red = value; |
| *green = value; |
| *blue = value; |
| } else { |
| if (hue == 360) hue = 0; |
| |
| hue = hue / 60; |
| i = (int)hue; |
| f = hue - i; |
| p = value * (1 - sat); |
| q = value * (1 - (sat * f)); |
| t = value * (1 - (sat * (1 - f))); |
| |
| switch (i) { |
| case 0: |
| *red = value; |
| *green = t; |
| *blue = p; |
| break; |
| case 1: |
| *red = q; |
| *green = value; |
| *blue = p; |
| break; |
| case 2: |
| *red = p; |
| *green = value; |
| *blue = t; |
| break; |
| case 3: |
| *red = p; |
| *green = q; |
| *blue = value; |
| break; |
| case 4: |
| *red = t; |
| *green = p; |
| *blue = value; |
| break; |
| case 5: |
| *red = value; |
| *green = p; |
| *blue = q; |
| break; |
| } |
| } |
| } |
| |
| class ChangeColorFx final : public TStandardRasterFx { |
| FX_PLUGIN_DECLARATION(ChangeColorFx) |
| TRasterFxPort m_input; |
| TPixelParamP m_from_color; |
| TPixelParamP m_to_color; |
| TDoubleParamP m_range; |
| TDoubleParamP m_falloff; |
| |
| public: |
| ChangeColorFx() |
| : m_from_color(TPixel32::Red) |
| , m_to_color(TPixel32::Blue) |
| , m_range(0.0) |
| , m_falloff(0.0) { |
| addInputPort("Source", m_input); |
| bindParam(this, "range", m_range); |
| bindParam(this, "falloff", m_falloff); |
| bindParam(this, "from_color", m_from_color); |
| bindParam(this, "to_color", m_to_color); |
| m_range->setValueRange(0, 100); |
| m_falloff->setValueRange(0, 100); |
| } |
| ~ChangeColorFx(){}; |
| |
| bool doGetBBox(double frame, TRectD &bBox, |
| const TRenderSettings &info) override { |
| if (m_input.isConnected()) return m_input->doGetBBox(frame, bBox, info); |
| { |
| bBox = TRectD(); |
| return false; |
| } |
| }; |
| |
| void doCompute(TTile &tile, double frame, const TRenderSettings &ri) override; |
| }; |
| |
| static double normalize_h(double h) { |
| if (h < 0) h += 360; |
| if (h > 360) h -= 360; |
| return h; |
| } |
| |
| |
| void ChangeColorFx::doCompute(TTile &tile, double frame, |
| const TRenderSettings &ri) { |
| if (!m_input.isConnected()) return; |
| |
| m_input->compute(tile, frame, ri); |
| |
| double from_h, from_s, from_v, to_h, to_s, to_v; |
| bool swaprange = false, swapfallmin = false, swapfallmax; |
| TPixel32 from_color = m_from_color->getPremultipliedValue(frame); |
| TPixel32 to_color = m_to_color->getPremultipliedValue(frame); |
| double range = m_range->getValue(frame) / 100; |
| double falloff = m_falloff->getValue(frame) / 100; |
| |
| OLDRGB2HSV(from_color.r / 255.0, from_color.g / 255.0, from_color.b / 255.0, |
| &from_h, &from_s, &from_v); |
| OLDRGB2HSV(to_color.r / 255.0, to_color.g / 255.0, to_color.b / 255.0, &to_h, |
| &to_s, &to_v); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| TRaster32P raster32 = tile.getRaster(); |
| assert(raster32); |
| |
| double hmin = from_h - range * 180; |
| hmin = normalize_h(hmin); |
| double hmax = from_h + range * 180; |
| hmax = normalize_h(hmax); |
| if (hmax <= hmin) { |
| std::swap(hmin, hmax); |
| swaprange = true; |
| } |
| double smin = from_s - range; |
| double smax = from_s + range; |
| double vmin = from_v - range; |
| double vmax = from_v + range; |
| double hfallmin = hmin - falloff * 180; |
| double hfallmax = hmax + falloff * 180; |
| hfallmin = normalize_h(hfallmin); |
| hfallmax = normalize_h(hfallmax); |
| if (hfallmin > hmin) { |
| swapfallmin = true; |
| } |
| if (hfallmax < hmax) { |
| swapfallmax = true; |
| } |
| double sfallmin = smin - falloff; |
| double sfallmax = smax + falloff; |
| double vfallmin = vmin - falloff; |
| double vfallmax = vmax + falloff; |
| |
| int j; |
| raster32->lock(); |
| for (j = 0; j < raster32->getLy(); j++) { |
| TPixel32 *pix = raster32->pixels(j); |
| TPixel32 *endPix = pix + raster32->getLx(); |
| while (pix < endPix) { |
| double r, g, b, h, s, v; |
| r = pix->r / 255.0; |
| g = pix->g / 255.0; |
| b = pix->b / 255.0; |
| |
| OLDRGB2HSV(r, g, b, &h, &s, &v); |
| int hflag = (h <= hmax && h >= hmin); |
| if (swaprange) hflag = !hflag; |
| if (hflag && s <= smax && s >= smin && v <= vmax && v >= vmin) |
| *pix = to_color; |
| else { |
| double hcorr = 0; |
| double scorr = 0; |
| double vcorr = 0; |
| int hfallminflag = (h <= hmin && h >= hfallmin); |
| if (hfallminflag) hcorr = h - hmin; |
| int hfallmaxflag = (h >= hmax && h <= hfallmax); |
| if (hfallmaxflag) hcorr = h - hmax; |
| if (hcorr) { |
| if (s <= smin && s >= sfallmin) scorr = s - smin; |
| if (s >= smax && s <= sfallmax) scorr = s - smax; |
| if (v <= vmin && v >= vfallmin) vcorr = v - vmin; |
| if (v >= vmax && v <= vfallmax) vcorr = v - vmax; |
| if (s < smin && s > sfallmin) scorr = s - smin; |
| if (s > smax && s < sfallmax) scorr = s - smax; |
| h = to_h + hcorr; |
| if (h < 0) h += 360; |
| if (h > 360) h -= 360; |
| OLDHSV2RGB(h, s, v, &r, &g, &b); |
| |
| pix->r = (UCHAR)(r * 255); |
| pix->g = (UCHAR)(g * 255); |
| pix->b = (UCHAR)(b * 255); |
| } |
| } |
| |
| *pix++; |
| } |
| } |
| raster32->unlock(); |
| } |
| |
| |
| |