Blender V2.61 - r43446

node_composite_glare.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2006 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): Alfredo de Greef  (eeshlo)
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include "node_composite_util.h"
00034 
00035 static bNodeSocketTemplate cmp_node_glare_in[]= {
00036     {   SOCK_RGBA, 1, "Image",          1.0f, 1.0f, 1.0f, 1.0f},
00037     {   -1, 0, ""   }
00038 };
00039 static bNodeSocketTemplate cmp_node_glare_out[]= {
00040     {   SOCK_RGBA, 0, "Image"},
00041     {   -1, 0, ""   }
00042 };
00043 
00044 
00045 // mix two images, src buffer does not have to be same size,
00046 static void mixImages(CompBuf *dst, CompBuf *src, float mix)
00047 {
00048     int x, y;
00049     fRGB c1, c2, *dcolp, *scolp;
00050     const float mf = 2.f - 2.f*fabsf(mix - 0.5f);
00051     if ((dst->x == src->x) && (dst->y == src->y)) {
00052         for (y=0; y<dst->y; y++) {
00053             dcolp = (fRGB*)&dst->rect[y*dst->x*dst->type];
00054             scolp = (fRGB*)&src->rect[y*dst->x*dst->type];
00055             for (x=0; x<dst->x; x++) {
00056                 fRGB_copy(c1, dcolp[x]);
00057                 fRGB_copy(c2, scolp[x]);
00058                 c1[0] += mix*(c2[0] - c1[0]);
00059                 c1[1] += mix*(c2[1] - c1[1]);
00060                 c1[2] += mix*(c2[2] - c1[2]);
00061                 if (c1[0] < 0.f) c1[0] = 0.f;
00062                 if (c1[1] < 0.f) c1[1] = 0.f;
00063                 if (c1[2] < 0.f) c1[2] = 0.f;
00064                 fRGB_mult(c1, mf);
00065                 fRGB_copy(dcolp[x], c1);
00066             }
00067         }
00068     }
00069     else {
00070         float xr = src->x / (float)dst->x;
00071         float yr = src->y / (float)dst->y;
00072         for (y=0; y<dst->y; y++) {
00073             dcolp = (fRGB*)&dst->rect[y*dst->x*dst->type];
00074             for (x=0; x<dst->x; x++) {
00075                 fRGB_copy(c1, dcolp[x]);
00076                 qd_getPixelLerp(src, (x + 0.5f)*xr - 0.5f, (y + 0.5f)*yr - 0.5f, c2);
00077                 c1[0] += mix*(c2[0] - c1[0]);
00078                 c1[1] += mix*(c2[1] - c1[1]);
00079                 c1[2] += mix*(c2[2] - c1[2]);
00080                 if (c1[0] < 0.f) c1[0] = 0.f;
00081                 if (c1[1] < 0.f) c1[1] = 0.f;
00082                 if (c1[2] < 0.f) c1[2] = 0.f;
00083                 fRGB_mult(c1, mf);
00084                 fRGB_copy(dcolp[x], c1);
00085             }
00086         }
00087     }
00088 }
00089 
00090 
00091 // adds src to dst image, must be of same size
00092 static void addImage(CompBuf* dst, CompBuf* src, float scale)
00093 {
00094     if ((dst->x == src->x) && (dst->y == src->y)) {
00095         int p = dst->x*dst->y*dst->type;
00096         float *dcol = dst->rect, *scol = src->rect;
00097         while (p--) *dcol++ += *scol++ * scale;
00098     }
00099 }
00100 
00101 
00102 // returns possibly downscaled copy of all pixels above threshold
00103 static CompBuf* BTP(CompBuf* src, float threshold, int scaledown)
00104 {
00105     int x, y;
00106     CompBuf* bsrc = qd_downScaledCopy(src, scaledown);
00107     float* cr = bsrc->rect;
00108     for (y=0; y<bsrc->y; ++y)
00109         for (x=0; x<bsrc->x; ++x, cr+=4) {
00110             if ((0.212671f*cr[0] + 0.71516f*cr[1] + 0.072169f*cr[2]) >= threshold) {
00111                 cr[0] -= threshold, cr[1] -= threshold, cr[2] -= threshold;
00112                 cr[0] = MAX2(cr[0], 0.f);
00113                 cr[1] = MAX2(cr[1], 0.f);
00114                 cr[2] = MAX2(cr[2], 0.f);
00115             }
00116             else cr[0] = cr[1] = cr[2] = 0.f;
00117         }
00118     return bsrc;
00119 }
00120 
00121 //--------------------------------------------------------------------------------------------
00122 // simple 4-point star filter
00123 
00124 static void star4(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
00125 {
00126     int x, y, i, xm, xp, ym, yp;
00127     float c[4] = {0,0,0,0}, tc[4] = {0,0,0,0};
00128     CompBuf *tbuf1, *tbuf2, *tsrc;
00129     const float f1 = 1.f - ndg->fade, f2 = (1.f - f1)*0.5f;
00130     //const float t3 = ndg->threshold*3.f;
00131     const float sc = (float)(1 << ndg->quality);
00132     const float isc = 1.f/sc;
00133 
00134     tsrc = BTP(src, ndg->threshold, (int)sc);
00135 
00136     tbuf1 = dupalloc_compbuf(tsrc);
00137     tbuf2 = dupalloc_compbuf(tsrc);
00138 
00139     for (i=0; i<ndg->iter; i++) {
00140         // (x || x-1, y-1) to (x || x+1, y+1)
00141         // F
00142         for (y=0; y<tbuf1->y; y++) {
00143             ym = y - i;
00144             yp = y + i;
00145             for (x=0; x<tbuf1->x; x++) {
00146                 xm = x - i;
00147                 xp = x + i;
00148                 qd_getPixel(tbuf1, x, y, c);
00149                 fRGB_mult(c, f1);
00150                 qd_getPixel(tbuf1, (ndg->angle ? xm : x), ym, tc);
00151                 fRGB_madd(c, tc, f2);
00152                 qd_getPixel(tbuf1, (ndg->angle ? xp : x), yp, tc);
00153                 fRGB_madd(c, tc, f2);
00154                 qd_setPixel(tbuf1, x, y, c);
00155             }
00156         }
00157         // B
00158         for (y=tbuf1->y-1; y>=0; y--) {
00159             ym = y - i;
00160             yp = y + i;
00161             for (x=tbuf1->x-1; x>=0; x--) {
00162                 xm = x - i;
00163                 xp = x + i;
00164                 qd_getPixel(tbuf1, x, y, c);
00165                 fRGB_mult(c, f1);
00166                 qd_getPixel(tbuf1, (ndg->angle ? xm : x), ym, tc);
00167                 fRGB_madd(c, tc, f2);
00168                 qd_getPixel(tbuf1, (ndg->angle ? xp : x), yp, tc);
00169                 fRGB_madd(c, tc, f2);
00170                 qd_setPixel(tbuf1, x, y, c);
00171             }
00172         }
00173         // (x-1, y || y+1) to (x+1, y || y-1)
00174         // F
00175         for (y=0; y<tbuf2->y; y++) {
00176             ym = y - i;
00177             yp = y + i;
00178             for (x=0; x<tbuf2->x; x++) {
00179                 xm = x - i;
00180                 xp = x + i;
00181                 qd_getPixel(tbuf2, x, y, c);
00182                 fRGB_mult(c, f1);
00183                 qd_getPixel(tbuf2, xm, (ndg->angle ? yp : y), tc);
00184                 fRGB_madd(c, tc, f2);
00185                 qd_getPixel(tbuf2, xp, (ndg->angle ? ym : y), tc);
00186                 fRGB_madd(c, tc, f2);
00187                 qd_setPixel(tbuf2, x, y, c);
00188             }
00189         }
00190         // B
00191         for (y=tbuf2->y-1; y>=0; y--) {
00192             ym = y - i;
00193             yp = y + i;
00194             for (x=tbuf2->x-1; x>=0; x--) {
00195                 xm = x - i;
00196                 xp = x + i;
00197                 qd_getPixel(tbuf2, x, y, c);
00198                 fRGB_mult(c, f1);
00199                 qd_getPixel(tbuf2, xm, (ndg->angle ? yp : y), tc);
00200                 fRGB_madd(c, tc, f2);
00201                 qd_getPixel(tbuf2, xp, (ndg->angle ? ym : y), tc);
00202                 fRGB_madd(c, tc, f2);
00203                 qd_setPixel(tbuf2, x, y, c);
00204             }
00205         }
00206     }
00207 
00208     for (y=0; y<tbuf1->y; ++y)
00209         for (x=0; x<tbuf1->x; ++x) {
00210             unsigned int p = (x + y*tbuf1->x)*tbuf1->type;
00211             tbuf1->rect[p] += tbuf2->rect[p];
00212             tbuf1->rect[p+1] += tbuf2->rect[p+1];
00213             tbuf1->rect[p+2] += tbuf2->rect[p+2];
00214         }
00215 
00216     for (y=0; y<dst->y; ++y) {
00217         const float m = 0.5f + 0.5f*ndg->mix;
00218         for (x=0; x<dst->x; ++x) {
00219             unsigned int p = (x + y*dst->x)*dst->type;
00220             qd_getPixelLerp(tbuf1, x*isc, y*isc, tc);
00221             dst->rect[p] = src->rect[p] + m*(tc[0] - src->rect[p]);
00222             dst->rect[p+1] = src->rect[p+1] + m*(tc[1] - src->rect[p+1]);
00223             dst->rect[p+2] = src->rect[p+2] + m*(tc[2] - src->rect[p+2]);
00224         }
00225     }
00226 
00227     free_compbuf(tbuf1);
00228     free_compbuf(tbuf2);
00229     free_compbuf(tsrc);
00230 }
00231 
00232 //--------------------------------------------------------------------------------------------
00233 // streak filter
00234 
00235 static void streaks(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
00236 {
00237     CompBuf *bsrc, *tsrc, *tdst, *sbuf;
00238     int x, y, n;
00239     unsigned int nump=0;
00240     fRGB c1, c2, c3, c4;
00241     float a, ang = DEG2RADF(360.0f)/(float)ndg->angle;
00242 
00243     bsrc = BTP(src, ndg->threshold, 1 << ndg->quality);
00244     tsrc = dupalloc_compbuf(bsrc); // sample from buffer
00245     tdst = alloc_compbuf(tsrc->x, tsrc->y, tsrc->type, 1); // sample to buffer
00246     sbuf = alloc_compbuf(tsrc->x, tsrc->y, tsrc->type, 1);  // streak sum buffer
00247 
00248     
00249     for (a=0.f; a<DEG2RADF(360.0f); a+=ang) {
00250         const float an = a + ndg->angle_ofs;
00251         const float vx = cos((double)an), vy = sin((double)an);
00252         for (n=0; n<ndg->iter; ++n) {
00253             const float p4 = pow(4.0, (double)n);
00254             const float vxp = vx*p4, vyp = vy*p4;
00255             const float wt = pow((double)ndg->fade, (double)p4);
00256             const float cmo = 1.f - (float)pow((double)ndg->colmod, (double)n+1);   // colormodulation amount relative to current pass
00257             float* tdstcol = tdst->rect;
00258             for (y=0; y<tsrc->y; ++y) {
00259                 for (x=0; x<tsrc->x; ++x, tdstcol+=4) {
00260                     // first pass no offset, always same for every pass, exact copy,
00261                     // otherwise results in uneven brightness, only need once
00262                     if (n==0) qd_getPixel(tsrc, x, y, c1); else c1[0]=c1[1]=c1[2]=0;
00263                     qd_getPixelLerp(tsrc, x + vxp,     y + vyp,     c2);
00264                     qd_getPixelLerp(tsrc, x + vxp*2.f, y + vyp*2.f, c3);
00265                     qd_getPixelLerp(tsrc, x + vxp*3.f, y + vyp*3.f, c4);
00266                     // modulate color to look vaguely similar to a color spectrum
00267                     fRGB_rgbmult(c2, 1.f, cmo, cmo);
00268                     fRGB_rgbmult(c3, cmo, cmo, 1.f);
00269                     fRGB_rgbmult(c4, cmo, 1.f, cmo);
00270                     tdstcol[0] = 0.5f*(tdstcol[0] + c1[0] + wt*(c2[0] + wt*(c3[0] + wt*c4[0])));
00271                     tdstcol[1] = 0.5f*(tdstcol[1] + c1[1] + wt*(c2[1] + wt*(c3[1] + wt*c4[1])));
00272                     tdstcol[2] = 0.5f*(tdstcol[2] + c1[2] + wt*(c2[2] + wt*(c3[2] + wt*c4[2])));
00273                 }
00274             }
00275             memcpy(tsrc->rect, tdst->rect, sizeof(float)*tdst->x*tdst->y*tdst->type);
00276         }
00277 
00278         addImage(sbuf, tsrc, 1.f/(float)(6 - ndg->iter));
00279         memset(tdst->rect, 0, tdst->x*tdst->y*tdst->type*sizeof(float));
00280         memcpy(tsrc->rect, bsrc->rect, bsrc->x*bsrc->y*bsrc->type*sizeof(float));
00281         nump++;
00282     }
00283 
00284     mixImages(dst, sbuf, 0.5f + 0.5f*ndg->mix);
00285 
00286     free_compbuf(tsrc);
00287     free_compbuf(tdst);
00288     free_compbuf(sbuf);
00289     free_compbuf(bsrc);
00290 }
00291 
00292 
00293 //--------------------------------------------------------------------------------------------
00294 // Ghosts (lensflare)
00295 
00296 static float smoothMask(float x, float y)
00297 {
00298     float t;
00299     x = 2.f*x - 1.f, y = 2.f*y - 1.f;
00300     if ((t = 1.f - sqrtf(x*x + y*y)) <= 0.f) return 0.f;
00301     return t;
00302 }
00303 
00304 static void ghosts(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
00305 {
00306     // colormodulation and scale factors (cm & scalef) for 16 passes max: 64
00307     int x, y, n, p, np;
00308     fRGB c, tc, cm[64];
00309     float sc, isc, u, v, sm, s, t, ofs, scalef[64];
00310     CompBuf *tbuf1, *tbuf2, *gbuf;
00311     const float cmo = 1.f - ndg->colmod;
00312     const int qt = 1 << ndg->quality;
00313     const float s1 = 4.f/(float)qt, s2 = 2.f*s1;
00314 
00315     gbuf = BTP(src, ndg->threshold, qt);
00316     tbuf1 = dupalloc_compbuf(gbuf);
00317     IIR_gauss(tbuf1, s1, 0, 3);
00318     IIR_gauss(tbuf1, s1, 1, 3);
00319     IIR_gauss(tbuf1, s1, 2, 3);
00320     tbuf2 = dupalloc_compbuf(tbuf1);
00321     IIR_gauss(tbuf2, s2, 0, 3);
00322     IIR_gauss(tbuf2, s2, 1, 3);
00323     IIR_gauss(tbuf2, s2, 2, 3);
00324 
00325     if (ndg->iter & 1) ofs = 0.5f; else ofs = 0.f;
00326     for (x=0; x<(ndg->iter*4); x++) {
00327         y = x & 3;
00328         cm[x][0] = cm[x][1] = cm[x][2] = 1;
00329         if (y==1) fRGB_rgbmult(cm[x], 1.f, cmo, cmo);
00330         if (y==2) fRGB_rgbmult(cm[x], cmo, cmo, 1.f);
00331         if (y==3) fRGB_rgbmult(cm[x], cmo, 1.f, cmo);
00332         scalef[x] = 2.1f*(1.f-(x+ofs)/(float)(ndg->iter*4));
00333         if (x & 1) scalef[x] = -0.99f/scalef[x];
00334     }
00335 
00336     sc = 2.13;
00337     isc = -0.97;
00338     for (y=0; y<gbuf->y; y++) {
00339         v = (float)(y+0.5f) / (float)gbuf->y;
00340         for (x=0; x<gbuf->x; x++) {
00341             u = (float)(x+0.5f) / (float)gbuf->x;
00342             s = (u-0.5f)*sc + 0.5f, t = (v-0.5f)*sc + 0.5f;
00343             qd_getPixelLerp(tbuf1, s*gbuf->x, t*gbuf->y, c);
00344             sm = smoothMask(s, t);
00345             fRGB_mult(c, sm);
00346             s = (u-0.5f)*isc + 0.5f, t = (v-0.5f)*isc + 0.5f;
00347             qd_getPixelLerp(tbuf2, s*gbuf->x - 0.5f, t*gbuf->y - 0.5f, tc);
00348             sm = smoothMask(s, t);
00349             fRGB_madd(c, tc, sm);
00350             qd_setPixel(gbuf, x, y, c);
00351         }
00352     }
00353 
00354     memset(tbuf1->rect, 0, tbuf1->x*tbuf1->y*tbuf1->type*sizeof(float));
00355     for (n=1; n<ndg->iter; n++) {
00356         for (y=0; y<gbuf->y; y++) {
00357             v = (float)(y+0.5f) / (float)gbuf->y;
00358             for (x=0; x<gbuf->x; x++) {
00359                 u = (float)(x+0.5f) / (float)gbuf->x;
00360                 tc[0] = tc[1] = tc[2] = 0.f;
00361                 for (p=0;p<4;p++) {
00362                     np = (n<<2) + p;
00363                     s = (u-0.5f)*scalef[np] + 0.5f;
00364                     t = (v-0.5f)*scalef[np] + 0.5f;
00365                     qd_getPixelLerp(gbuf, s*gbuf->x - 0.5f, t*gbuf->y - 0.5f, c);
00366                     fRGB_colormult(c, cm[np]);
00367                     sm = smoothMask(s, t)*0.25f;
00368                     fRGB_madd(tc, c, sm);
00369                 }
00370                 p = (x + y*tbuf1->x)*tbuf1->type;
00371                 tbuf1->rect[p] += tc[0];
00372                 tbuf1->rect[p+1] += tc[1];
00373                 tbuf1->rect[p+2] += tc[2];
00374             }
00375         }
00376         memcpy(gbuf->rect, tbuf1->rect, tbuf1->x*tbuf1->y*tbuf1->type*sizeof(float));
00377     }
00378 
00379     free_compbuf(tbuf1);
00380     free_compbuf(tbuf2);
00381 
00382     mixImages(dst, gbuf, 0.5f + 0.5f*ndg->mix);
00383     free_compbuf(gbuf);
00384 }
00385 
00386 //--------------------------------------------------------------------------------------------
00387 // Fog glow (convolution with kernel of exponential falloff)
00388 
00389 static void fglow(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
00390 {
00391     int x, y;
00392     float scale, u, v, r, w, d;
00393     fRGB fcol;
00394     CompBuf *tsrc, *ckrn;
00395     unsigned int sz = 1 << ndg->size;
00396     const float cs_r = 1.f, cs_g = 1.f, cs_b = 1.f;
00397 
00398     // temp. src image
00399     tsrc = BTP(src, ndg->threshold, 1 << ndg->quality);
00400     // make the convolution kernel
00401     ckrn = alloc_compbuf(sz, sz, CB_RGBA, 1);
00402 
00403     scale = 0.25f*sqrtf(sz*sz);
00404 
00405     for (y=0; y<sz; ++y) {
00406         v = 2.f*(y / (float)sz) - 1.f;
00407         for (x=0; x<sz; ++x) {
00408             u = 2.f*(x / (float)sz) - 1.f;
00409             r = (u*u + v*v)*scale;
00410             d = -sqrtf(sqrtf(sqrtf(r)))*9.f;
00411             fcol[0] = expf(d*cs_r), fcol[1] = expf(d*cs_g), fcol[2] = expf(d*cs_b);
00412             // linear window good enough here, visual result counts, not scientific analysis
00413             //w = (1.f-fabs(u))*(1.f-fabs(v));
00414             // actually, Hanning window is ok, cos^2 for some reason is slower
00415             w = (0.5f + 0.5f*cos((double)u*M_PI))*(0.5f + 0.5f*cos((double)v*M_PI));
00416             fRGB_mult(fcol, w);
00417             qd_setPixel(ckrn, x, y, fcol);
00418         }
00419     }
00420 
00421     convolve(tsrc, tsrc, ckrn);
00422     free_compbuf(ckrn);
00423     mixImages(dst, tsrc, 0.5f + 0.5f*ndg->mix);
00424     free_compbuf(tsrc);
00425 }
00426 
00427 //--------------------------------------------------------------------------------------------
00428 
00429 static void node_composit_exec_glare(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
00430 {
00431     CompBuf *new, *src, *img = in[0]->data;
00432     NodeGlare* ndg = node->storage;
00433 
00434     if ((img == NULL) || (out[0]->hasoutput == 0)) return;
00435 
00436     if (img->type != CB_RGBA) {
00437         new = typecheck_compbuf(img, CB_RGBA);
00438         src = typecheck_compbuf(img, CB_RGBA);
00439     } else {
00440         new = dupalloc_compbuf(img);
00441         src = dupalloc_compbuf(img);
00442     }
00443 
00444     {
00445         int x, y;
00446         for (y=0; y<new->y; ++y) {
00447             fRGB* col = (fRGB*)&new->rect[y*new->x*new->type];
00448             for (x=0; x<new->x; ++x) {
00449                 col[x][0] = MAX2(col[x][0], 0.f);
00450                 col[x][1] = MAX2(col[x][1], 0.f);
00451                 col[x][2] = MAX2(col[x][2], 0.f);
00452             }
00453         }
00454     }
00455 
00456     switch (ndg->type) {
00457         case 0:
00458             star4(ndg, new, src);
00459             break;
00460         case 1:
00461             fglow(ndg, new, src);
00462             break;
00463         case 3:
00464             ghosts(ndg, new, src);
00465             break;
00466         case 2:
00467         default:
00468             streaks(ndg, new, src);
00469             break;
00470     }
00471 
00472     free_compbuf(src);
00473     out[0]->data = new;
00474 }
00475 
00476 static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
00477 {
00478     NodeGlare *ndg = MEM_callocN(sizeof(NodeGlare), "node glare data");
00479     ndg->quality = 1;
00480     ndg->type = 2;
00481     ndg->iter = 3;
00482     ndg->colmod = 0.25;
00483     ndg->mix = 0;
00484     ndg->threshold = 1;
00485     ndg->angle = 4;
00486     ndg->angle_ofs = 0.0f;
00487     ndg->fade = 0.9;
00488     ndg->size = 8;
00489     node->storage = ndg;
00490 }
00491 
00492 void register_node_type_cmp_glare(bNodeTreeType *ttype)
00493 {
00494     static bNodeType ntype;
00495 
00496     node_type_base(ttype, &ntype, CMP_NODE_GLARE, "Glare", NODE_CLASS_OP_FILTER, NODE_OPTIONS);
00497     node_type_socket_templates(&ntype, cmp_node_glare_in, cmp_node_glare_out);
00498     node_type_size(&ntype, 150, 120, 200);
00499     node_type_init(&ntype, node_composit_init_glare);
00500     node_type_storage(&ntype, "NodeGlare", node_free_standard_storage, node_copy_standard_storage);
00501     node_type_exec(&ntype, node_composit_exec_glare);
00502 
00503     nodeRegisterType(ttype, &ntype);
00504 }