33
33
#include "node_composite_util.h"
35
static bNodeSocketTemplate cmp_node_glare_in[]= {
36
{ SOCK_RGBA, 1, "Image", 1.0f, 1.0f, 1.0f, 1.0f},
39
static bNodeSocketTemplate cmp_node_glare_out[]= {
40
{ SOCK_RGBA, 0, "Image"},
45
// mix two images, src buffer does not have to be same size,
46
static void mixImages(CompBuf *dst, CompBuf *src, float mix)
49
fRGB c1, c2, *dcolp, *scolp;
50
const float mf = 2.f - 2.f*fabsf(mix - 0.5f);
51
if ((dst->x == src->x) && (dst->y == src->y)) {
52
for (y=0; y<dst->y; y++) {
53
dcolp = (fRGB*)&dst->rect[y*dst->x*dst->type];
54
scolp = (fRGB*)&src->rect[y*dst->x*dst->type];
55
for (x=0; x<dst->x; x++) {
56
fRGB_copy(c1, dcolp[x]);
57
fRGB_copy(c2, scolp[x]);
58
c1[0] += mix*(c2[0] - c1[0]);
59
c1[1] += mix*(c2[1] - c1[1]);
60
c1[2] += mix*(c2[2] - c1[2]);
61
if (c1[0] < 0.f) c1[0] = 0.f;
62
if (c1[1] < 0.f) c1[1] = 0.f;
63
if (c1[2] < 0.f) c1[2] = 0.f;
65
fRGB_copy(dcolp[x], c1);
70
float xr = src->x / (float)dst->x;
71
float yr = src->y / (float)dst->y;
72
for (y=0; y<dst->y; y++) {
73
dcolp = (fRGB*)&dst->rect[y*dst->x*dst->type];
74
for (x=0; x<dst->x; x++) {
75
fRGB_copy(c1, dcolp[x]);
76
qd_getPixelLerp(src, (x + 0.5f)*xr - 0.5f, (y + 0.5f)*yr - 0.5f, c2);
77
c1[0] += mix*(c2[0] - c1[0]);
78
c1[1] += mix*(c2[1] - c1[1]);
79
c1[2] += mix*(c2[2] - c1[2]);
80
if (c1[0] < 0.f) c1[0] = 0.f;
81
if (c1[1] < 0.f) c1[1] = 0.f;
82
if (c1[2] < 0.f) c1[2] = 0.f;
84
fRGB_copy(dcolp[x], c1);
91
// adds src to dst image, must be of same size
92
static void addImage(CompBuf* dst, CompBuf* src, float scale)
94
if ((dst->x == src->x) && (dst->y == src->y)) {
95
int p = dst->x*dst->y*dst->type;
96
float *dcol = dst->rect, *scol = src->rect;
97
while (p--) *dcol++ += *scol++ * scale;
102
// returns possibly downscaled copy of all pixels above threshold
103
static CompBuf* BTP(CompBuf* src, float threshold, int scaledown)
106
CompBuf* bsrc = qd_downScaledCopy(src, scaledown);
107
float* cr = bsrc->rect;
108
for (y=0; y<bsrc->y; ++y)
109
for (x=0; x<bsrc->x; ++x, cr+=4) {
110
if ((0.212671f*cr[0] + 0.71516f*cr[1] + 0.072169f*cr[2]) >= threshold) {
111
cr[0] -= threshold, cr[1] -= threshold, cr[2] -= threshold;
112
cr[0] = MAX2(cr[0], 0.f);
113
cr[1] = MAX2(cr[1], 0.f);
114
cr[2] = MAX2(cr[2], 0.f);
116
else cr[0] = cr[1] = cr[2] = 0.f;
121
//--------------------------------------------------------------------------------------------
122
// simple 4-point star filter
124
static void star4(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
126
int x, y, i, xm, xp, ym, yp;
127
float c[4] = {0,0,0,0}, tc[4] = {0,0,0,0};
128
CompBuf *tbuf1, *tbuf2, *tsrc;
129
const float f1 = 1.f - ndg->fade, f2 = (1.f - f1)*0.5f;
130
//const float t3 = ndg->threshold*3.f;
131
const float sc = (float)(1 << ndg->quality);
132
const float isc = 1.f/sc;
134
tsrc = BTP(src, ndg->threshold, (int)sc);
136
tbuf1 = dupalloc_compbuf(tsrc);
137
tbuf2 = dupalloc_compbuf(tsrc);
139
for (i=0; i<ndg->iter; i++) {
140
// (x || x-1, y-1) to (x || x+1, y+1)
142
for (y=0; y<tbuf1->y; y++) {
145
for (x=0; x<tbuf1->x; x++) {
148
qd_getPixel(tbuf1, x, y, c);
150
qd_getPixel(tbuf1, (ndg->angle ? xm : x), ym, tc);
151
fRGB_madd(c, tc, f2);
152
qd_getPixel(tbuf1, (ndg->angle ? xp : x), yp, tc);
153
fRGB_madd(c, tc, f2);
154
qd_setPixel(tbuf1, x, y, c);
158
for (y=tbuf1->y-1; y>=0; y--) {
161
for (x=tbuf1->x-1; x>=0; x--) {
164
qd_getPixel(tbuf1, x, y, c);
166
qd_getPixel(tbuf1, (ndg->angle ? xm : x), ym, tc);
167
fRGB_madd(c, tc, f2);
168
qd_getPixel(tbuf1, (ndg->angle ? xp : x), yp, tc);
169
fRGB_madd(c, tc, f2);
170
qd_setPixel(tbuf1, x, y, c);
173
// (x-1, y || y+1) to (x+1, y || y-1)
175
for (y=0; y<tbuf2->y; y++) {
178
for (x=0; x<tbuf2->x; x++) {
181
qd_getPixel(tbuf2, x, y, c);
183
qd_getPixel(tbuf2, xm, (ndg->angle ? yp : y), tc);
184
fRGB_madd(c, tc, f2);
185
qd_getPixel(tbuf2, xp, (ndg->angle ? ym : y), tc);
186
fRGB_madd(c, tc, f2);
187
qd_setPixel(tbuf2, x, y, c);
191
for (y=tbuf2->y-1; y>=0; y--) {
194
for (x=tbuf2->x-1; x>=0; x--) {
197
qd_getPixel(tbuf2, x, y, c);
199
qd_getPixel(tbuf2, xm, (ndg->angle ? yp : y), tc);
200
fRGB_madd(c, tc, f2);
201
qd_getPixel(tbuf2, xp, (ndg->angle ? ym : y), tc);
202
fRGB_madd(c, tc, f2);
203
qd_setPixel(tbuf2, x, y, c);
208
for (y=0; y<tbuf1->y; ++y)
209
for (x=0; x<tbuf1->x; ++x) {
210
unsigned int p = (x + y*tbuf1->x)*tbuf1->type;
211
tbuf1->rect[p] += tbuf2->rect[p];
212
tbuf1->rect[p+1] += tbuf2->rect[p+1];
213
tbuf1->rect[p+2] += tbuf2->rect[p+2];
216
for (y=0; y<dst->y; ++y) {
217
const float m = 0.5f + 0.5f*ndg->mix;
218
for (x=0; x<dst->x; ++x) {
219
unsigned int p = (x + y*dst->x)*dst->type;
220
qd_getPixelLerp(tbuf1, x*isc, y*isc, tc);
221
dst->rect[p] = src->rect[p] + m*(tc[0] - src->rect[p]);
222
dst->rect[p+1] = src->rect[p+1] + m*(tc[1] - src->rect[p+1]);
223
dst->rect[p+2] = src->rect[p+2] + m*(tc[2] - src->rect[p+2]);
232
//--------------------------------------------------------------------------------------------
235
static void streaks(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
237
CompBuf *bsrc, *tsrc, *tdst, *sbuf;
241
float a, ang = DEG2RADF(360.0f)/(float)ndg->angle;
243
bsrc = BTP(src, ndg->threshold, 1 << ndg->quality);
244
tsrc = dupalloc_compbuf(bsrc); // sample from buffer
245
tdst = alloc_compbuf(tsrc->x, tsrc->y, tsrc->type, 1); // sample to buffer
246
sbuf = alloc_compbuf(tsrc->x, tsrc->y, tsrc->type, 1); // streak sum buffer
249
for (a=0.f; a<DEG2RADF(360.0f); a+=ang) {
250
const float an = a + ndg->angle_ofs;
251
const float vx = cos((double)an), vy = sin((double)an);
252
for (n=0; n<ndg->iter; ++n) {
253
const float p4 = pow(4.0, (double)n);
254
const float vxp = vx*p4, vyp = vy*p4;
255
const float wt = pow((double)ndg->fade, (double)p4);
256
const float cmo = 1.f - (float)pow((double)ndg->colmod, (double)n+1); // colormodulation amount relative to current pass
257
float* tdstcol = tdst->rect;
258
for (y=0; y<tsrc->y; ++y) {
259
for (x=0; x<tsrc->x; ++x, tdstcol+=4) {
260
// first pass no offset, always same for every pass, exact copy,
261
// otherwise results in uneven brightness, only need once
262
if (n==0) qd_getPixel(tsrc, x, y, c1); else c1[0]=c1[1]=c1[2]=0;
263
qd_getPixelLerp(tsrc, x + vxp, y + vyp, c2);
264
qd_getPixelLerp(tsrc, x + vxp*2.f, y + vyp*2.f, c3);
265
qd_getPixelLerp(tsrc, x + vxp*3.f, y + vyp*3.f, c4);
266
// modulate color to look vaguely similar to a color spectrum
267
fRGB_rgbmult(c2, 1.f, cmo, cmo);
268
fRGB_rgbmult(c3, cmo, cmo, 1.f);
269
fRGB_rgbmult(c4, cmo, 1.f, cmo);
270
tdstcol[0] = 0.5f*(tdstcol[0] + c1[0] + wt*(c2[0] + wt*(c3[0] + wt*c4[0])));
271
tdstcol[1] = 0.5f*(tdstcol[1] + c1[1] + wt*(c2[1] + wt*(c3[1] + wt*c4[1])));
272
tdstcol[2] = 0.5f*(tdstcol[2] + c1[2] + wt*(c2[2] + wt*(c3[2] + wt*c4[2])));
275
memcpy(tsrc->rect, tdst->rect, sizeof(float)*tdst->x*tdst->y*tdst->type);
278
addImage(sbuf, tsrc, 1.f/(float)(6 - ndg->iter));
279
memset(tdst->rect, 0, tdst->x*tdst->y*tdst->type*sizeof(float));
280
memcpy(tsrc->rect, bsrc->rect, bsrc->x*bsrc->y*bsrc->type*sizeof(float));
284
mixImages(dst, sbuf, 0.5f + 0.5f*ndg->mix);
293
//--------------------------------------------------------------------------------------------
294
// Ghosts (lensflare)
296
static float smoothMask(float x, float y)
299
x = 2.f*x - 1.f, y = 2.f*y - 1.f;
300
if ((t = 1.f - sqrtf(x*x + y*y)) <= 0.f) return 0.f;
304
static void ghosts(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
306
// colormodulation and scale factors (cm & scalef) for 16 passes max: 64
309
float sc, isc, u, v, sm, s, t, ofs, scalef[64];
310
CompBuf *tbuf1, *tbuf2, *gbuf;
311
const float cmo = 1.f - ndg->colmod;
312
const int qt = 1 << ndg->quality;
313
const float s1 = 4.f/(float)qt, s2 = 2.f*s1;
315
gbuf = BTP(src, ndg->threshold, qt);
316
tbuf1 = dupalloc_compbuf(gbuf);
317
IIR_gauss(tbuf1, s1, 0, 3);
318
IIR_gauss(tbuf1, s1, 1, 3);
319
IIR_gauss(tbuf1, s1, 2, 3);
320
tbuf2 = dupalloc_compbuf(tbuf1);
321
IIR_gauss(tbuf2, s2, 0, 3);
322
IIR_gauss(tbuf2, s2, 1, 3);
323
IIR_gauss(tbuf2, s2, 2, 3);
325
if (ndg->iter & 1) ofs = 0.5f; else ofs = 0.f;
326
for (x=0; x<(ndg->iter*4); x++) {
328
cm[x][0] = cm[x][1] = cm[x][2] = 1;
329
if (y==1) fRGB_rgbmult(cm[x], 1.f, cmo, cmo);
330
if (y==2) fRGB_rgbmult(cm[x], cmo, cmo, 1.f);
331
if (y==3) fRGB_rgbmult(cm[x], cmo, 1.f, cmo);
332
scalef[x] = 2.1f*(1.f-(x+ofs)/(float)(ndg->iter*4));
333
if (x & 1) scalef[x] = -0.99f/scalef[x];
338
for (y=0; y<gbuf->y; y++) {
339
v = (float)(y+0.5f) / (float)gbuf->y;
340
for (x=0; x<gbuf->x; x++) {
341
u = (float)(x+0.5f) / (float)gbuf->x;
342
s = (u-0.5f)*sc + 0.5f, t = (v-0.5f)*sc + 0.5f;
343
qd_getPixelLerp(tbuf1, s*gbuf->x, t*gbuf->y, c);
344
sm = smoothMask(s, t);
346
s = (u-0.5f)*isc + 0.5f, t = (v-0.5f)*isc + 0.5f;
347
qd_getPixelLerp(tbuf2, s*gbuf->x - 0.5f, t*gbuf->y - 0.5f, tc);
348
sm = smoothMask(s, t);
349
fRGB_madd(c, tc, sm);
350
qd_setPixel(gbuf, x, y, c);
354
memset(tbuf1->rect, 0, tbuf1->x*tbuf1->y*tbuf1->type*sizeof(float));
355
for (n=1; n<ndg->iter; n++) {
356
for (y=0; y<gbuf->y; y++) {
357
v = (float)(y+0.5f) / (float)gbuf->y;
358
for (x=0; x<gbuf->x; x++) {
359
u = (float)(x+0.5f) / (float)gbuf->x;
360
tc[0] = tc[1] = tc[2] = 0.f;
363
s = (u-0.5f)*scalef[np] + 0.5f;
364
t = (v-0.5f)*scalef[np] + 0.5f;
365
qd_getPixelLerp(gbuf, s*gbuf->x - 0.5f, t*gbuf->y - 0.5f, c);
366
fRGB_colormult(c, cm[np]);
367
sm = smoothMask(s, t)*0.25f;
368
fRGB_madd(tc, c, sm);
370
p = (x + y*tbuf1->x)*tbuf1->type;
371
tbuf1->rect[p] += tc[0];
372
tbuf1->rect[p+1] += tc[1];
373
tbuf1->rect[p+2] += tc[2];
376
memcpy(gbuf->rect, tbuf1->rect, tbuf1->x*tbuf1->y*tbuf1->type*sizeof(float));
382
mixImages(dst, gbuf, 0.5f + 0.5f*ndg->mix);
386
//--------------------------------------------------------------------------------------------
387
// Fog glow (convolution with kernel of exponential falloff)
389
static void fglow(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
392
float scale, u, v, r, w, d;
394
CompBuf *tsrc, *ckrn;
395
unsigned int sz = 1 << ndg->size;
396
const float cs_r = 1.f, cs_g = 1.f, cs_b = 1.f;
399
tsrc = BTP(src, ndg->threshold, 1 << ndg->quality);
400
// make the convolution kernel
401
ckrn = alloc_compbuf(sz, sz, CB_RGBA, 1);
403
scale = 0.25f*sqrtf(sz*sz);
405
for (y=0; y<sz; ++y) {
406
v = 2.f*(y / (float)sz) - 1.f;
407
for (x=0; x<sz; ++x) {
408
u = 2.f*(x / (float)sz) - 1.f;
409
r = (u*u + v*v)*scale;
410
d = -sqrtf(sqrtf(sqrtf(r)))*9.f;
411
fcol[0] = expf(d*cs_r), fcol[1] = expf(d*cs_g), fcol[2] = expf(d*cs_b);
412
// linear window good enough here, visual result counts, not scientific analysis
413
//w = (1.f-fabs(u))*(1.f-fabs(v));
414
// actually, Hanning window is ok, cos^2 for some reason is slower
415
w = (0.5f + 0.5f*cos((double)u*M_PI))*(0.5f + 0.5f*cos((double)v*M_PI));
417
qd_setPixel(ckrn, x, y, fcol);
421
convolve(tsrc, tsrc, ckrn);
423
mixImages(dst, tsrc, 0.5f + 0.5f*ndg->mix);
427
//--------------------------------------------------------------------------------------------
429
static void node_composit_exec_glare(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
431
CompBuf *new, *src, *img = in[0]->data;
432
NodeGlare* ndg = node->storage;
434
if ((img == NULL) || (out[0]->hasoutput == 0)) return;
436
if (img->type != CB_RGBA) {
437
new = typecheck_compbuf(img, CB_RGBA);
438
src = typecheck_compbuf(img, CB_RGBA);
441
new = dupalloc_compbuf(img);
442
src = dupalloc_compbuf(img);
447
for (y=0; y<new->y; ++y) {
448
fRGB* col = (fRGB*)&new->rect[y*new->x*new->type];
449
for (x=0; x<new->x; ++x) {
450
col[x][0] = MAX2(col[x][0], 0.f);
451
col[x][1] = MAX2(col[x][1], 0.f);
452
col[x][2] = MAX2(col[x][2], 0.f);
459
star4(ndg, new, src);
462
fglow(ndg, new, src);
465
ghosts(ndg, new, src);
469
streaks(ndg, new, src);
477
static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
35
static bNodeSocketTemplate cmp_node_glare_in[] = {
36
{ SOCK_RGBA, 1, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
39
static bNodeSocketTemplate cmp_node_glare_out[] = {
40
{ SOCK_RGBA, 0, N_("Image")},
44
static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node, bNodeTemplate *UNUSED(ntemp))
479
46
NodeGlare *ndg = MEM_callocN(sizeof(NodeGlare), "node glare data");