48     : x(-0.5), y(-0.5), brightness(1.0), size(1.0), spread(1.0),
 
   49       color(
Color(
"#ffffff"))
 
   51     init_effect_details();
 
   63     : x(xPos), y(yPos), brightness(intensity), size(scale),
 
   64       spread(spreadVal), color(tint)
 
   66     init_effect_details();
 
   73 void LensFlare::init_effect_details()
 
   78     info.
description = 
"Simulate sunlight hitting a lens with flares and spectral colors.";
 
   91 static inline QRgb blendAdd(QRgb dst, 
const QColor &c, 
float p)
 
   93     int dr = (255 - qRed(dst)) * p * c.redF();
 
   94     int dg = (255 - qGreen(dst)) * p * c.greenF();
 
   95     int db = (255 - qBlue(dst)) * p * c.blueF();
 
   96     int da = (255 - qAlpha(dst)) * p * c.alphaF();
 
   98         std::clamp(qRed(dst) + dr, 0, 255),
 
   99         std::clamp(qGreen(dst) + dg, 0, 255),
 
  100         std::clamp(qBlue(dst) + db, 0, 255),
 
  101         std::clamp(qAlpha(dst) + da, 0, 255)
 
  106 static QColor shifted_hsv(
const QColor &base, 
float h_shift,
 
  107                           float s_scale, 
float v_scale,
 
  108                           float a_scale = 1.0f)
 
  111     base.getHsvF(&h, &s, &v, &a);
 
  114     h = std::fmod(h + h_shift + 1.0, 1.0);
 
  115     s = std::clamp(s * s_scale, 0.0, 1.0);
 
  116     v = std::clamp(v * v_scale, 0.0, 1.0);
 
  117     a = std::clamp(a * a_scale, 0.0, 1.0);
 
  120     out.setHsvF(h, s, v, a);
 
  125 static void init_reflectors(std::vector<Reflect> &refs, 
float DX, 
float DY,
 
  126                             int width, 
int height, 
const QColor &tint,
 
  129     float halfW = width * 0.5f;
 
  130     float halfH = height * 0.5f;
 
  133     struct Rdef { 
int type; 
float fx, fy, fsize, r, g, b; };
 
  135         {1,  0.6699f,  0.6699f, 0.027f,   0.0f,       14/255.0f, 113/255.0f},
 
  136         {1,  0.2692f,  0.2692f, 0.010f,  90/255.0f, 181/255.0f, 142/255.0f},
 
  137         {1, -0.0112f, -0.0112f, 0.005f,  56/255.0f, 140/255.0f, 106/255.0f},
 
  138         {2,  0.6490f,  0.6490f, 0.031f,   9/255.0f,  29/255.0f,  19/255.0f},
 
  139         {2,  0.4696f,  0.4696f, 0.015f,  24/255.0f,  14/255.0f,   0.0f},
 
  140         {2,  0.4087f,  0.4087f, 0.037f,  24/255.0f,  14/255.0f,   0.0f},
 
  141         {2, -0.2003f, -0.2003f, 0.022f,  42/255.0f,  19/255.0f,   0.0f},
 
  142         {2, -0.4103f, -0.4103f, 0.025f,   0.0f,        9/255.0f,  17/255.0f},
 
  143         {2, -0.4503f, -0.4503f, 0.058f,  10/255.0f,   4/255.0f,   0.0f},
 
  144         {2, -0.5112f, -0.5112f, 0.017f,   5/255.0f,   5/255.0f,  14/255.0f},
 
  145         {2, -1.4960f, -1.4960f, 0.20f,    9/255.0f,   4/255.0f,   0.0f},
 
  146         {2, -1.4960f, -1.4960f, 0.50f,    9/255.0f,   4/255.0f,   0.0f},
 
  147         {3,  0.4487f,  0.4487f, 0.075f,  34/255.0f,  19/255.0f,   0.0f},
 
  148         {3,  1.0000f,  1.0000f, 0.10f,   14/255.0f,  26/255.0f,   0.0f},
 
  149         {3, -1.3010f, -1.3010f, 0.039f,  10/255.0f,  25/255.0f,  13/255.0f},
 
  150         {4,  1.3090f,  1.3090f, 0.19f,    9/255.0f,   0.0f,      17/255.0f},
 
  151         {4,  1.3090f,  1.3090f, 0.195f,   9/255.0f,   16/255.0f,   5/255.0f},
 
  152         {4,  1.3090f,  1.3090f, 0.20f,   17/255.0f,    4/255.0f,   0.0f},
 
  153         {4, -1.3010f, -1.3010f, 0.038f,  17/255.0f,    4/255.0f,   0.0f}
 
  157     refs.reserve(std::size(defs));
 
  158     bool whiteTint = (tint.saturationF() < 0.01f);
 
  160     for (
auto &d : defs) {
 
  163         r.
size = d.fsize * matt * S;
 
  164         r.
xp = halfW + d.fx * DX;
 
  165         r.
yp = halfH + d.fy * DY;
 
  167         QColor base = QColor::fromRgbF(d.r, d.g, d.b, 1.0f);
 
  168         r.
col = whiteTint ? base
 
  179 static void apply_reflector(QRgb &pxl, 
const Reflect &r, 
int cx, 
int cy)
 
  181     float d = std::hypot(r.
xp - cx, r.
yp - cy);
 
  189             pxl = blendAdd(pxl, r.
col, p);
 
  193         p = (r.
size - d) / (r.
size * 0.15f);
 
  195             p = std::min(p, 1.0f);
 
  196             pxl = blendAdd(pxl, r.
col, p);
 
  200         p = (r.
size - d) / (r.
size * 0.12f);
 
  202             p = std::min(p, 1.0f);
 
  203             p = 1.0f - (p * 0.12f);
 
  204             pxl = blendAdd(pxl, r.
col, p);
 
  208         p = std::abs((d - r.
size) / (r.
size * 0.04f));
 
  210             pxl = blendAdd(pxl, r.
col, 1.0f - p);
 
  217 std::shared_ptr<openshot::Frame>
 
  220     auto img = frame->GetImage();
 
  221     int w = img->width();
 
  222     int h = img->height();
 
  232     float halfW = w * 0.5f, halfH = h * 0.5f;
 
  233     float px    = (X * 0.5f + 0.5f) * w;
 
  234     float py    = (Y * 0.5f + 0.5f) * h;
 
  235     float DX    = (halfW - px) * SP;
 
  236     float DY    = (halfH - py) * SP;
 
  239     QColor tint = QColor::fromRgbF(
 
  248     float scolor = matt * 0.0375f * S;
 
  249     float sglow  = matt * 0.078125f * S;
 
  250     float sinner = matt * 0.1796875f * S;
 
  251     float souter = matt * 0.3359375f * S;
 
  252     float shalo  = matt * 0.084375f * S;
 
  255     auto tintify = [&](
float br, 
float bg, 
float bb) {
 
  256         return QColor::fromRgbF(
 
  264     QColor c_color = tintify(239/255.0f, 239/255.0f, 239/255.0f);
 
  265     QColor c_glow  = tintify(245/255.0f, 245/255.0f, 245/255.0f);
 
  266     QColor c_inner = tintify(1.0f,       38/255.0f,   43/255.0f);
 
  267     QColor c_outer = tintify(69/255.0f,  59/255.0f,   64/255.0f);
 
  268     QColor c_halo  = tintify(80/255.0f,  15/255.0f,    4/255.0f);
 
  271     std::vector<Reflect> refs;
 
  272     init_reflectors(refs, DX, DY, w, h, tint, S);
 
  275     QImage overlay(w, h, QImage::Format_ARGB32);
 
  276     overlay.fill(Qt::transparent);
 
  278     #pragma omp parallel for schedule(dynamic) 
  279     for (
int yy = 0; yy < h; ++yy) {
 
  280         QRgb *scan = 
reinterpret_cast<QRgb*
>(overlay.scanLine(yy));
 
  281         for (
int xx = 0; xx < w; ++xx) {
 
  284             float d = std::hypot(xx - px, yy - py);
 
  288                 float p = (scolor - d)/scolor; p*=p;
 
  289                 QRgb tmp = blendAdd(qRgba(r,g,b,0), c_color, p);
 
  290                 r = qRed(tmp); g = qGreen(tmp); b = qBlue(tmp);
 
  294                 float p = (sglow - d)/sglow; p*=p;
 
  295                 QRgb tmp = blendAdd(qRgba(r,g,b,0), c_glow, p);
 
  296                 r = qRed(tmp); g = qGreen(tmp); b = qBlue(tmp);
 
  300                 float p = (sinner - d)/sinner; p*=p;
 
  301                 QRgb tmp = blendAdd(qRgba(r,g,b,0), c_inner, p);
 
  302                 r = qRed(tmp); g = qGreen(tmp); b = qBlue(tmp);
 
  306                 float p = (souter - d)/souter;
 
  307                 QRgb tmp = blendAdd(qRgba(r,g,b,0), c_outer, p);
 
  308                 r = qRed(tmp); g = qGreen(tmp); b = qBlue(tmp);
 
  312                 float p = std::abs((d - shalo)/(shalo*0.07f));
 
  314                     QRgb tmp = blendAdd(qRgba(r,g,b,0), c_halo, 1.0f-p);
 
  315                     r = qRed(tmp); g = qGreen(tmp); b = qBlue(tmp);
 
  319             for (
auto &rf : refs) {
 
  320                 QRgb tmp = qRgba(r,g,b,0);
 
  321                 apply_reflector(tmp, rf, xx, yy);
 
  322                 r = qRed(tmp); g = qGreen(tmp); b = qBlue(tmp);
 
  326             int a = std::max({r,g,b});
 
  327             scan[xx] = qRgba(r,g,b,a);
 
  332     QImage origAlpha = img->convertToFormat(QImage::Format_Alpha8);
 
  335     QPainter p(img.get());
 
  336     p.setCompositionMode(QPainter::CompositionMode_Plus);
 
  338     p.drawImage(0, 0, overlay);
 
  342     QImage finalA(w,h, QImage::Format_Alpha8);
 
  343     auto overlayA = overlay.convertToFormat(QImage::Format_Alpha8);
 
  345     for (
int yy=0; yy<h; ++yy) {
 
  346         uchar *oL = origAlpha.scanLine(yy);
 
  347         uchar *fL = overlayA.scanLine(yy);
 
  348         uchar *nL = finalA.scanLine(yy);
 
  349         for (
int xx=0; xx<w; ++xx) {
 
  350             float oa = oL[xx]/255.0f;
 
  351             float fa = (fL[xx]/255.0f)*I;
 
  352             nL[xx] = 
static_cast<uchar
>(std::clamp(std::max(oa,fa)*255.0f, 0.0f, 255.0f));
 
  355     img->setAlphaChannel(finalA);
 
  360 std::shared_ptr<openshot::Frame>
 
  363     return GetFrame(std::make_shared<openshot::Frame>(), frame_number);
 
  390     catch (...) { 
throw InvalidJSON(
"LensFlare JSON"); }
 
  419     return r.toStyledString();