static void streaks(NodeGlare* ndg, CompBuf* dst, CompBuf* src) { CompBuf *bsrc, *tsrc, *tdst, *sbuf; int x, y, n; unsigned int nump=0; fRGB c1, c2, c3, c4; float a, ang = 360.f/(float)ndg->angle; bsrc = BTP(src, ndg->threshold, 1 << ndg->quality); tsrc = dupalloc_compbuf(bsrc); // sample from buffer tdst = alloc_compbuf(tsrc->x, tsrc->y, tsrc->type, 1); // sample to buffer sbuf = alloc_compbuf(tsrc->x, tsrc->y, tsrc->type, 1); // streak sum buffer for (a=0.f; a<360.f; a+=ang) { const float an = (a + (float)ndg->angle_ofs)*(float)M_PI/180.f; const float vx = cos((double)an), vy = sin((double)an); for (n=0; n<ndg->iter; ++n) { const float p4 = pow(4.0, (double)n); const float vxp = vx*p4, vyp = vy*p4; const float wt = pow((double)ndg->fade, (double)p4); const float cmo = 1.f - pow((double)ndg->colmod, (double)n+1); // colormodulation amount relative to current pass float* tdstcol = tdst->rect; for (y=0; y<tsrc->y; ++y) { for (x=0; x<tsrc->x; ++x, tdstcol+=4) { // first pass no offset, always same for every pass, exact copy, // otherwise results in uneven brightness, only need once if (n==0) qd_getPixel(tsrc, x, y, c1); else c1[0]=c1[1]=c1[2]=0; qd_getPixelLerp(tsrc, x + vxp, y + vyp, c2); qd_getPixelLerp(tsrc, x + vxp*2.f, y + vyp*2.f, c3); qd_getPixelLerp(tsrc, x + vxp*3.f, y + vyp*3.f, c4); // modulate color to look vaguely similar to a color spectrum fRGB_rgbmult(c2, 1.f, cmo, cmo); fRGB_rgbmult(c3, cmo, cmo, 1.f); fRGB_rgbmult(c4, cmo, 1.f, cmo); tdstcol[0] = 0.5f*(tdstcol[0] + c1[0] + wt*(c2[0] + wt*(c3[0] + wt*c4[0]))); tdstcol[1] = 0.5f*(tdstcol[1] + c1[1] + wt*(c2[1] + wt*(c3[1] + wt*c4[1]))); tdstcol[2] = 0.5f*(tdstcol[2] + c1[2] + wt*(c2[2] + wt*(c3[2] + wt*c4[2]))); } } memcpy(tsrc->rect, tdst->rect, sizeof(float)*tdst->x*tdst->y*tdst->type); } addImage(sbuf, tsrc, 1.f/(float)(6 - ndg->iter)); memset(tdst->rect, 0, tdst->x*tdst->y*tdst->type*sizeof(float)); memcpy(tsrc->rect, bsrc->rect, bsrc->x*bsrc->y*bsrc->type*sizeof(float)); nump++; } mixImages(dst, sbuf, 0.5f + 0.5f*ndg->mix); free_compbuf(tsrc); free_compbuf(tdst); free_compbuf(sbuf); free_compbuf(bsrc); }
// mix two images, src buffer does not have to be same size, static void mixImages(CompBuf *dst, CompBuf *src, float mix) { int x, y; fRGB c1, c2, *dcolp, *scolp; const float mf = 2.f - 2.f*fabsf(mix - 0.5f); if ((dst->x == src->x) && (dst->y == src->y)) { for (y=0; y<dst->y; y++) { dcolp = (fRGB*)&dst->rect[y*dst->x*dst->type]; scolp = (fRGB*)&src->rect[y*dst->x*dst->type]; for (x=0; x<dst->x; x++) { fRGB_copy(c1, dcolp[x]); fRGB_copy(c2, scolp[x]); c1[0] += mix*(c2[0] - c1[0]); c1[1] += mix*(c2[1] - c1[1]); c1[2] += mix*(c2[2] - c1[2]); if (c1[0] < 0.f) c1[0] = 0.f; if (c1[1] < 0.f) c1[1] = 0.f; if (c1[2] < 0.f) c1[2] = 0.f; fRGB_mult(c1, mf); fRGB_copy(dcolp[x], c1); } } } else { float xr = src->x / (float)dst->x; float yr = src->y / (float)dst->y; for (y=0; y<dst->y; y++) { dcolp = (fRGB*)&dst->rect[y*dst->x*dst->type]; for (x=0; x<dst->x; x++) { fRGB_copy(c1, dcolp[x]); qd_getPixelLerp(src, (x + 0.5f)*xr - 0.5f, (y + 0.5f)*yr - 0.5f, c2); c1[0] += mix*(c2[0] - c1[0]); c1[1] += mix*(c2[1] - c1[1]); c1[2] += mix*(c2[2] - c1[2]); if (c1[0] < 0.f) c1[0] = 0.f; if (c1[1] < 0.f) c1[1] = 0.f; if (c1[2] < 0.f) c1[2] = 0.f; fRGB_mult(c1, mf); fRGB_copy(dcolp[x], c1); } } } }
static void ghosts(NodeGlare* ndg, CompBuf* dst, CompBuf* src) { // colormodulation and scale factors (cm & scalef) for 16 passes max: 64 int x, y, n, p, np; fRGB c, tc, cm[64]; float sc, isc, u, v, sm, s, t, ofs, scalef[64]; CompBuf *tbuf1, *tbuf2, *gbuf; const float cmo = 1.f - ndg->colmod; const int qt = 1 << ndg->quality; const float s1 = 4.f/(float)qt, s2 = 2.f*s1; gbuf = BTP(src, ndg->threshold, qt); tbuf1 = dupalloc_compbuf(gbuf); IIR_gauss(tbuf1, s1, 0, 3); IIR_gauss(tbuf1, s1, 1, 3); IIR_gauss(tbuf1, s1, 2, 3); tbuf2 = dupalloc_compbuf(tbuf1); IIR_gauss(tbuf2, s2, 0, 3); IIR_gauss(tbuf2, s2, 1, 3); IIR_gauss(tbuf2, s2, 2, 3); if (ndg->iter & 1) ofs = 0.5f; else ofs = 0.f; for (x=0; x<(ndg->iter*4); x++) { y = x & 3; cm[x][0] = cm[x][1] = cm[x][2] = 1; if (y==1) fRGB_rgbmult(cm[x], 1.f, cmo, cmo); if (y==2) fRGB_rgbmult(cm[x], cmo, cmo, 1.f); if (y==3) fRGB_rgbmult(cm[x], cmo, 1.f, cmo); scalef[x] = 2.1f*(1.f-(x+ofs)/(float)(ndg->iter*4)); if (x & 1) scalef[x] = -0.99f/scalef[x]; } sc = 2.13; isc = -0.97; for (y=0; y<gbuf->y; y++) { v = (float)(y+0.5f) / (float)gbuf->y; for (x=0; x<gbuf->x; x++) { u = (float)(x+0.5f) / (float)gbuf->x; s = (u-0.5f)*sc + 0.5f, t = (v-0.5f)*sc + 0.5f; qd_getPixelLerp(tbuf1, s*gbuf->x, t*gbuf->y, c); sm = smoothMask(s, t); fRGB_mult(c, sm); s = (u-0.5f)*isc + 0.5f, t = (v-0.5f)*isc + 0.5f; qd_getPixelLerp(tbuf2, s*gbuf->x - 0.5f, t*gbuf->y - 0.5f, tc); sm = smoothMask(s, t); fRGB_madd(c, tc, sm); qd_setPixel(gbuf, x, y, c); } } memset(tbuf1->rect, 0, tbuf1->x*tbuf1->y*tbuf1->type*sizeof(float)); for (n=1; n<ndg->iter; n++) { for (y=0; y<gbuf->y; y++) { v = (float)(y+0.5f) / (float)gbuf->y; for (x=0; x<gbuf->x; x++) { u = (float)(x+0.5f) / (float)gbuf->x; tc[0] = tc[1] = tc[2] = 0.f; for (p=0;p<4;p++) { np = (n<<2) + p; s = (u-0.5f)*scalef[np] + 0.5f; t = (v-0.5f)*scalef[np] + 0.5f; qd_getPixelLerp(gbuf, s*gbuf->x - 0.5f, t*gbuf->y - 0.5f, c); fRGB_colormult(c, cm[np]); sm = smoothMask(s, t)*0.25f; fRGB_madd(tc, c, sm); } p = (x + y*tbuf1->x)*tbuf1->type; tbuf1->rect[p] += tc[0]; tbuf1->rect[p+1] += tc[1]; tbuf1->rect[p+2] += tc[2]; } } memcpy(gbuf->rect, tbuf1->rect, tbuf1->x*tbuf1->y*tbuf1->type*sizeof(float)); } free_compbuf(tbuf1); free_compbuf(tbuf2); mixImages(dst, gbuf, 0.5f + 0.5f*ndg->mix); free_compbuf(gbuf); }
static void star4(NodeGlare* ndg, CompBuf* dst, CompBuf* src) { int x, y, i, xm, xp, ym, yp; float c[4] = {0,0,0,0}, tc[4] = {0,0,0,0}; CompBuf *tbuf1, *tbuf2, *tsrc; const float f1 = 1.f - ndg->fade, f2 = (1.f - f1)*0.5f; //const float t3 = ndg->threshold*3.f; const float sc = (float)(1 << ndg->quality); const float isc = 1.f/sc; tsrc = BTP(src, ndg->threshold, (int)sc); tbuf1 = dupalloc_compbuf(tsrc); tbuf2 = dupalloc_compbuf(tsrc); for (i=0; i<ndg->iter; i++) { // (x || x-1, y-1) to (x || x+1, y+1) // F for (y=0; y<tbuf1->y; y++) { ym = y - i; yp = y + i; for (x=0; x<tbuf1->x; x++) { xm = x - i; xp = x + i; qd_getPixel(tbuf1, x, y, c); fRGB_mult(c, f1); qd_getPixel(tbuf1, (ndg->angle ? xm : x), ym, tc); fRGB_madd(c, tc, f2); qd_getPixel(tbuf1, (ndg->angle ? xp : x), yp, tc); fRGB_madd(c, tc, f2); qd_setPixel(tbuf1, x, y, c); } } // B for (y=tbuf1->y-1; y>=0; y--) { ym = y - i; yp = y + i; for (x=tbuf1->x-1; x>=0; x--) { xm = x - i; xp = x + i; qd_getPixel(tbuf1, x, y, c); fRGB_mult(c, f1); qd_getPixel(tbuf1, (ndg->angle ? xm : x), ym, tc); fRGB_madd(c, tc, f2); qd_getPixel(tbuf1, (ndg->angle ? xp : x), yp, tc); fRGB_madd(c, tc, f2); qd_setPixel(tbuf1, x, y, c); } } // (x-1, y || y+1) to (x+1, y || y-1) // F for (y=0; y<tbuf2->y; y++) { ym = y - i; yp = y + i; for (x=0; x<tbuf2->x; x++) { xm = x - i; xp = x + i; qd_getPixel(tbuf2, x, y, c); fRGB_mult(c, f1); qd_getPixel(tbuf2, xm, (ndg->angle ? yp : y), tc); fRGB_madd(c, tc, f2); qd_getPixel(tbuf2, xp, (ndg->angle ? ym : y), tc); fRGB_madd(c, tc, f2); qd_setPixel(tbuf2, x, y, c); } } // B for (y=tbuf2->y-1; y>=0; y--) { ym = y - i; yp = y + i; for (x=tbuf2->x-1; x>=0; x--) { xm = x - i; xp = x + i; qd_getPixel(tbuf2, x, y, c); fRGB_mult(c, f1); qd_getPixel(tbuf2, xm, (ndg->angle ? yp : y), tc); fRGB_madd(c, tc, f2); qd_getPixel(tbuf2, xp, (ndg->angle ? ym : y), tc); fRGB_madd(c, tc, f2); qd_setPixel(tbuf2, x, y, c); } } } for (y=0; y<tbuf1->y; ++y) for (x=0; x<tbuf1->x; ++x) { unsigned int p = (x + y*tbuf1->x)*tbuf1->type; tbuf1->rect[p] += tbuf2->rect[p]; tbuf1->rect[p+1] += tbuf2->rect[p+1]; tbuf1->rect[p+2] += tbuf2->rect[p+2]; } for (y=0; y<dst->y; ++y) { const float m = 0.5f + 0.5f*ndg->mix; for (x=0; x<dst->x; ++x) { unsigned int p = (x + y*dst->x)*dst->type; qd_getPixelLerp(tbuf1, x*isc, y*isc, tc); dst->rect[p] = src->rect[p] + m*(tc[0] - src->rect[p]); dst->rect[p+1] = src->rect[p+1] + m*(tc[1] - src->rect[p+1]); dst->rect[p+2] = src->rect[p+2] + m*(tc[2] - src->rect[p+2]); } } free_compbuf(tbuf1); free_compbuf(tbuf2); free_compbuf(tsrc); }
static void lensDistort(CompBuf* dst, CompBuf* src, float kr, float kg, float kb, int jit, int proj, int fit) { int x, y, z; const float cx = 0.5f*(float)dst->x, cy = 0.5f*(float)dst->y; if (proj) { // shift CompBuf* tsrc = dupalloc_compbuf(src); for (z=0; z<tsrc->type; ++z) IIR_gauss(tsrc, (kr+0.5f)*(kr+0.5f), z, 1); kr *= 20.f; for (y=0; y<dst->y; y++) { fRGB* colp = (fRGB*)&dst->rect[y*dst->x*dst->type]; const float v = (y + 0.5f)/(float)dst->y; for (x=0; x<dst->x; x++) { const float u = (x + 0.5f)/(float)dst->x; qd_getPixelLerpChan(tsrc, (u*dst->x + kr) - 0.5f, v*dst->y - 0.5f, 0, colp[x]); if (tsrc->type == CB_VAL) colp[x][1] = tsrc->rect[x + y*tsrc->x]; else colp[x][1] = tsrc->rect[(x + y*tsrc->x)*tsrc->type + 1]; qd_getPixelLerpChan(tsrc, (u*dst->x - kr) - 0.5f, v*dst->y - 0.5f, 2, colp[x]+2); } } free_compbuf(tsrc); } else { // Spherical // Scale factor to make bottom/top & right/left sides fit in window after deform // so in the case of pincushion (kn < 0), corners will be outside window. // Now also optionally scales image such that black areas are not visible when distort factor is positive // (makes distorted corners match window corners, but really only valid if mk<=0.5) const float mk = MAX3(kr, kg, kb); const float sc = (fit && (mk > 0.f)) ? (1.f/(1.f + 2.f*mk)) : (1.f/(1.f + mk)); const float drg = 4.f*(kg - kr), dgb = 4.f*(kb - kg); kr *= 4.f, kg *= 4.f, kb *= 4.f; for (y=0; y<dst->y; y++) { fRGB* colp = (fRGB*)&dst->rect[y*dst->x*dst->type]; const float v = sc*((y + 0.5f) - cy)/cy; for (x=0; x<dst->x; x++) { int dr = 0, dg = 0, db = 0; float d, t, ln[6] = {0, 0, 0, 0, 0, 0}; fRGB c1, tc = {0, 0, 0, 0}; const float u = sc*((x + 0.5f) - cx)/cx; int sta = 0, mid = 0, end = 0; if ((t = 1.f - kr*(u*u + v*v)) >= 0.f) { d = 1.f/(1.f + sqrtf(t)); ln[0] = (u*d + 0.5f)*dst->x - 0.5f, ln[1] = (v*d + 0.5f)*dst->y - 0.5f; sta = 1; } if ((t = 1.f - kg*(u*u + v*v)) >= 0.f) { d = 1.f/(1.f + sqrtf(t)); ln[2] = (u*d + 0.5f)*dst->x - 0.5f, ln[3] = (v*d + 0.5f)*dst->y - 0.5f; mid = 1; } if ((t = 1.f - kb*(u*u + v*v)) >= 0.f) { d = 1.f/(1.f + sqrtf(t)); ln[4] = (u*d + 0.5f)*dst->x - 0.5f, ln[5] = (v*d + 0.5f)*dst->y - 0.5f; end = 1; } if (sta && mid && end) { // RG const int dx = ln[2] - ln[0], dy = ln[3] - ln[1]; const float dsf = sqrtf(dx*dx + dy*dy) + 1.f; const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf); const float sd = 1.f/(float)ds; for (z=0; z<ds; ++z) { const float tz = ((float)z + (jit ? BLI_frand() : 0.5f))*sd; t = 1.f - (kr + tz*drg)*(u*u + v*v); d = 1.f / (1.f + sqrtf(t)); qd_getPixelLerp(src, (u*d + 0.5f)*dst->x - 0.5f, (v*d + 0.5f)*dst->y - 0.5f, c1); if (src->type == CB_VAL) c1[1] = c1[2] = c1[0]; tc[0] += (1.f-tz)*c1[0], tc[1] += tz*c1[1]; dr++, dg++; } // GB { const int dx = ln[4] - ln[2], dy = ln[5] - ln[3]; const float dsf = sqrtf(dx*dx + dy*dy) + 1.f; const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf); const float sd = 1.f/(float)ds; for (z=0; z<ds; ++z) { const float tz = ((float)z + (jit ? BLI_frand() : 0.5f))*sd; t = 1.f - (kg + tz*dgb)*(u*u + v*v); d = 1.f / (1.f + sqrtf(t)); qd_getPixelLerp(src, (u*d + 0.5f)*dst->x - 0.5f, (v*d + 0.5f)*dst->y - 0.5f, c1); if (src->type == CB_VAL) c1[1] = c1[2] = c1[0]; tc[1] += (1.f-tz)*c1[1], tc[2] += tz*c1[2]; dg++, db++; } } } if (dr) colp[x][0] = 2.f*tc[0] / (float)dr; if (dg) colp[x][1] = 2.f*tc[1] / (float)dg; if (db) colp[x][2] = 2.f*tc[2] / (float)db; } } } }