#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 < 0)
// hue=0;
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);
/*
int from_hsv[3];
int to_hsv[3];
rgb2hsv(from_hsv, from_color);
rgb2hsv(to_hsv, to_color);
/////////////// verificare ///////
from_h =((double)from_hsv[0]/255.)*360.;
from_s =from_hsv[1]/255.;
from_v =from_hsv[2]/255.;
to_h =((double)to_hsv[0]/255.)*360.;
to_s =to_hsv[1]/255.;
to_v =to_hsv[2]/255.;
*/
////////////////////////
TRaster32P raster32 = tile.getRaster();
assert(raster32); // per ora gestisco solo i Raster32
double hmin = from_h - range * 180;
hmin = normalize_h(hmin);
double hmax = from_h + range * 180;
hmax = normalize_h(hmax);
if (hmax <= hmin) {
tswap(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;
// int hsv[3];
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);
}
}
// premultiply(*pix);
*pix++;
}
}
raster32->unlock();
}
// FX_PLUGIN_IDENTIFIER(ChangeColorFx , "changeColorFx")