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