Blender V2.61 - r43446
|
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 }