nodes from eechlo
* glare * tonemap * lense distort * fast gauss blur http://projects.blender.org/tracker/?func=detail&atid=127&aid=7505&group_id=9 made fast gauss blur an option for the blur node rather then a separate node.
This commit is contained in:
@@ -303,6 +303,10 @@ void set_node_shader_lamp_loop(void (*lamp_loop_func)(struct ShadeInput *, str
|
||||
#define CMP_NODE_INVERT 251
|
||||
#define CMP_NODE_NORMALIZE 252
|
||||
|
||||
#define CMP_NODE_GLARE 301
|
||||
#define CMP_NODE_TONEMAP 302
|
||||
#define CMP_NODE_LENSDIST 303
|
||||
|
||||
/* channel toggles */
|
||||
#define CMP_CHAN_RGB 1
|
||||
#define CMP_CHAN_A 2
|
||||
|
||||
@@ -2365,6 +2365,10 @@ static void registerCompositNodes(ListBase *ntypelist)
|
||||
nodeRegisterType(ntypelist, &cmp_node_flip);
|
||||
nodeRegisterType(ntypelist, &cmp_node_displace);
|
||||
nodeRegisterType(ntypelist, &cmp_node_mapuv);
|
||||
|
||||
nodeRegisterType(ntypelist, &cmp_node_glare);
|
||||
nodeRegisterType(ntypelist, &cmp_node_tonemap);
|
||||
nodeRegisterType(ntypelist, &cmp_node_lensdist);
|
||||
}
|
||||
|
||||
static void registerShaderNodes(ListBase *ntypelist)
|
||||
|
||||
@@ -161,8 +161,10 @@ static void FLOAT2RGBE(fCOLOR fcol, RGBE rgbe)
|
||||
|
||||
int imb_is_a_hdr(void *buf)
|
||||
{
|
||||
/* For recognition, Blender only loades first 32 bytes, so use #?RADIANCE id instead */
|
||||
if (strstr((char*)buf, "#?RADIANCE")) return 1;
|
||||
// For recognition, Blender only loads first 32 bytes, so use #?RADIANCE id instead
|
||||
// update: actually, the 'RADIANCE' part is just an optional program name, the magic word is really only the '#?' part
|
||||
//if (strstr((char*)buf, "#?RADIANCE")) return 1;
|
||||
if (strstr((char*)buf, "#?")) return 1;
|
||||
// if (strstr((char*)buf, "32-bit_rle_rgbe")) return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -176,7 +178,6 @@ struct ImBuf *imb_loadhdr(unsigned char *mem, int size, int flags)
|
||||
int found=0;
|
||||
int width=0, height=0;
|
||||
int x, y;
|
||||
int ir, ig, ib;
|
||||
unsigned char* ptr;
|
||||
unsigned char* rect;
|
||||
char oriY[80], oriX[80];
|
||||
@@ -225,18 +226,14 @@ struct ImBuf *imb_loadhdr(unsigned char *mem, int size, int flags)
|
||||
*rect_float++ = fcol[GRN];
|
||||
*rect_float++ = fcol[BLU];
|
||||
*rect_float++ = 1.0f;
|
||||
|
||||
/* Also old oldstyle for the rest of blender which is not using floats yet */
|
||||
/* very weird mapping! (ton) */
|
||||
fcol[RED] = 1.f-exp(fcol[RED]*-1.414213562f);
|
||||
fcol[GRN] = 1.f-exp(fcol[GRN]*-1.414213562f);
|
||||
fcol[BLU] = 1.f-exp(fcol[BLU]*-1.414213562f);
|
||||
ir = (int)(255.f*pow(fcol[RED], 0.45454545f));
|
||||
ig = (int)(255.f*pow(fcol[GRN], 0.45454545f));
|
||||
ib = (int)(255.f*pow(fcol[BLU], 0.45454545f));
|
||||
*rect++ = (unsigned char)((ir<0) ? 0 : ((ir>255) ? 255 : ir));
|
||||
*rect++ = (unsigned char)((ig<0) ? 0 : ((ig>255) ? 255 : ig));
|
||||
*rect++ = (unsigned char)((ib<0) ? 0 : ((ib>255) ? 255 : ib));
|
||||
// e: changed to simpler tonemapping, previous code was rather slow (is this actually still relevant at all?)
|
||||
fcol[RED] = fcol[RED]/(1.f + fcol[RED]);
|
||||
fcol[GRN] = fcol[GRN]/(1.f + fcol[GRN]);
|
||||
fcol[BLU] = fcol[BLU]/(1.f + fcol[BLU]);
|
||||
*rect++ = (unsigned char)((fcol[RED] < 0.f) ? 0 : ((fcol[RED] > 1.f) ? 255 : (255.f*fcol[RED])));
|
||||
*rect++ = (unsigned char)((fcol[GRN] < 0.f) ? 0 : ((fcol[GRN] > 1.f) ? 255 : (255.f*fcol[GRN])));
|
||||
*rect++ = (unsigned char)((fcol[BLU] < 0.f) ? 0 : ((fcol[BLU] > 1.f) ? 255 : (255.f*fcol[BLU])));
|
||||
*rect++ = 255;
|
||||
}
|
||||
}
|
||||
@@ -328,10 +325,10 @@ static void writeHeader(FILE *file, int width, int height)
|
||||
fputc(10, file);
|
||||
fprintf(file, "# %s", "Created with Blender");
|
||||
fputc(10, file);
|
||||
fprintf(file, "FORMAT=32-bit_rle_rgbe");
|
||||
fputc(10, file);
|
||||
fprintf(file, "EXPOSURE=%25.13f", 1.0);
|
||||
fputc(10, file);
|
||||
fprintf(file, "FORMAT=32-bit_rle_rgbe");
|
||||
fputc(10, file);
|
||||
fputc(10, file);
|
||||
fprintf(file, "-Y %d +X %d", height, width);
|
||||
fputc(10, file);
|
||||
|
||||
@@ -230,4 +230,24 @@ typedef struct NodeDefocus {
|
||||
float fstop, maxblur, bthresh, scale;
|
||||
} NodeDefocus;
|
||||
|
||||
|
||||
/* qdn: glare node */
|
||||
typedef struct NodeGlare {
|
||||
char quality, type, iter;
|
||||
char angle, angle_ofs, size, pad[2];
|
||||
float colmod, mix, threshold, fade;
|
||||
} NodeGlare;
|
||||
|
||||
/* qdn: tonemap node */
|
||||
typedef struct NodeTonemap {
|
||||
float key, offset, gamma;
|
||||
float f, m, a, c;
|
||||
int type;
|
||||
} NodeTonemap;
|
||||
|
||||
/* qdn: lens distortion node */
|
||||
typedef struct NodeLensDist {
|
||||
short jit, proj, fit, pad;
|
||||
} NodeLensDist;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -507,6 +507,7 @@ typedef struct Scene {
|
||||
#define R_FILTER_CATROM 4
|
||||
#define R_FILTER_GAUSS 5
|
||||
#define R_FILTER_MITCH 6
|
||||
#define R_FILTER_FAST_GAUSS 7 /* note, this is only used for nodes at the moment */
|
||||
|
||||
/* yafray: renderer flag (not only exclusive to yafray) */
|
||||
#define R_INTERN 0
|
||||
|
||||
@@ -97,6 +97,8 @@ extern bNodeType cmp_node_flip;
|
||||
extern bNodeType cmp_node_displace;
|
||||
extern bNodeType cmp_node_mapuv;
|
||||
|
||||
extern bNodeType cmp_node_glare;
|
||||
extern bNodeType cmp_node_tonemap;
|
||||
extern bNodeType cmp_node_lensdist;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
|
||||
#include "../CMP_util.h"
|
||||
|
||||
|
||||
|
||||
/* **************** BLUR ******************** */
|
||||
static bNodeSocketType cmp_node_blur_in[]= {
|
||||
{ SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
|
||||
@@ -555,8 +553,6 @@ static void blur_with_reference(bNode *node, CompBuf *new, CompBuf *img, CompBuf
|
||||
free_compbuf(ref_use);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
||||
{
|
||||
CompBuf *new, *img= in[0]->data;
|
||||
@@ -564,35 +560,48 @@ static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bN
|
||||
if(img==NULL || out[0]->hasoutput==0)
|
||||
return;
|
||||
|
||||
if(img->type==CB_VEC2 || img->type==CB_VEC3) {
|
||||
img= typecheck_compbuf(in[0]->data, CB_RGBA);
|
||||
}
|
||||
if (((NodeBlurData *)node->storage)->filtertype == R_FILTER_FAST_GAUSS) {
|
||||
CompBuf *new, *img = in[0]->data;
|
||||
/*from eeshlo's original patch, removed to fit in with the existing blur node */
|
||||
/*const float sx = in[1]->vec[0], sy = in[2]->vec[0];*/
|
||||
|
||||
/* if fac input, we do it different */
|
||||
if(in[1]->data) {
|
||||
|
||||
/* make output size of input image */
|
||||
new= alloc_compbuf(img->x, img->y, img->type, 1); /* allocs */
|
||||
|
||||
/* accept image offsets from other nodes */
|
||||
new->xof = img->xof;
|
||||
new->yof = img->yof;
|
||||
|
||||
blur_with_reference(node, new, img, in[1]->data);
|
||||
if(node->exec & NODE_BREAK) {
|
||||
free_compbuf(new);
|
||||
new= NULL;
|
||||
}
|
||||
out[0]->data= new;
|
||||
}
|
||||
else {
|
||||
|
||||
if(in[1]->vec[0]<=0.001f) { /* time node inputs can be a tiny value */
|
||||
new= pass_on_compbuf(img);
|
||||
NodeBlurData *nbd= node->storage;
|
||||
const float sx = ((float)nbd->sizex)/2.0f, sy = ((float)nbd->sizey)/2.0f;
|
||||
int c;
|
||||
|
||||
if ((img==NULL) || (out[0]->hasoutput==0)) return;
|
||||
|
||||
if (img->type == CB_VEC2)
|
||||
new = typecheck_compbuf(img, CB_VAL);
|
||||
else if (img->type == CB_VEC3)
|
||||
new = typecheck_compbuf(img, CB_RGBA);
|
||||
else
|
||||
new = dupalloc_compbuf(img);
|
||||
|
||||
if ((sx == sy) && (sx > 0.f)) {
|
||||
for (c=0; c<new->type; ++c)
|
||||
IIR_gauss(new, sx, c, 3);
|
||||
}
|
||||
else {
|
||||
NodeBlurData *nbd= node->storage;
|
||||
CompBuf *gammabuf;
|
||||
if (sx > 0.f) {
|
||||
for (c=0; c<new->type; ++c)
|
||||
IIR_gauss(new, sx, c, 1);
|
||||
}
|
||||
if (sy > 0.f) {
|
||||
for (c=0; c<new->type; ++c)
|
||||
IIR_gauss(new, sy, c, 2);
|
||||
}
|
||||
}
|
||||
out[0]->data = new;
|
||||
|
||||
} else {
|
||||
/* All non fast gauss blur methods */
|
||||
if(img->type==CB_VEC2 || img->type==CB_VEC3) {
|
||||
img= typecheck_compbuf(in[0]->data, CB_RGBA);
|
||||
}
|
||||
|
||||
/* if fac input, we do it different */
|
||||
if(in[1]->data) {
|
||||
|
||||
/* make output size of input image */
|
||||
new= alloc_compbuf(img->x, img->y, img->type, 1); /* allocs */
|
||||
@@ -600,33 +609,57 @@ static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bN
|
||||
/* accept image offsets from other nodes */
|
||||
new->xof = img->xof;
|
||||
new->yof = img->yof;
|
||||
|
||||
if(nbd->gamma) {
|
||||
gammabuf= dupalloc_compbuf(img);
|
||||
gamma_correct_compbuf(gammabuf, 0);
|
||||
}
|
||||
else gammabuf= img;
|
||||
|
||||
if(nbd->bokeh)
|
||||
bokeh_single_image(node, new, gammabuf, in[1]->vec[0]);
|
||||
else if(1)
|
||||
blur_single_image(node, new, gammabuf, in[1]->vec[0]);
|
||||
else /* bloom experimental... */
|
||||
bloom_with_reference(new, gammabuf, NULL, in[1]->vec[0], nbd);
|
||||
|
||||
if(nbd->gamma) {
|
||||
gamma_correct_compbuf(new, 1);
|
||||
free_compbuf(gammabuf);
|
||||
}
|
||||
blur_with_reference(node, new, img, in[1]->data);
|
||||
if(node->exec & NODE_BREAK) {
|
||||
free_compbuf(new);
|
||||
new= NULL;
|
||||
}
|
||||
out[0]->data= new;
|
||||
}
|
||||
out[0]->data= new;
|
||||
else {
|
||||
|
||||
if(in[1]->vec[0]<=0.001f) { /* time node inputs can be a tiny value */
|
||||
new= pass_on_compbuf(img);
|
||||
}
|
||||
else {
|
||||
NodeBlurData *nbd= node->storage;
|
||||
CompBuf *gammabuf;
|
||||
|
||||
/* make output size of input image */
|
||||
new= alloc_compbuf(img->x, img->y, img->type, 1); /* allocs */
|
||||
|
||||
/* accept image offsets from other nodes */
|
||||
new->xof = img->xof;
|
||||
new->yof = img->yof;
|
||||
|
||||
if(nbd->gamma) {
|
||||
gammabuf= dupalloc_compbuf(img);
|
||||
gamma_correct_compbuf(gammabuf, 0);
|
||||
}
|
||||
else gammabuf= img;
|
||||
|
||||
if(nbd->bokeh)
|
||||
bokeh_single_image(node, new, gammabuf, in[1]->vec[0]);
|
||||
else if(1)
|
||||
blur_single_image(node, new, gammabuf, in[1]->vec[0]);
|
||||
else /* bloom experimental... */
|
||||
bloom_with_reference(new, gammabuf, NULL, in[1]->vec[0], nbd);
|
||||
|
||||
if(nbd->gamma) {
|
||||
gamma_correct_compbuf(new, 1);
|
||||
free_compbuf(gammabuf);
|
||||
}
|
||||
if(node->exec & NODE_BREAK) {
|
||||
free_compbuf(new);
|
||||
new= NULL;
|
||||
}
|
||||
}
|
||||
out[0]->data= new;
|
||||
}
|
||||
if(img!=in[0]->data)
|
||||
free_compbuf(img);
|
||||
}
|
||||
if(img!=in[0]->data)
|
||||
free_compbuf(img);
|
||||
}
|
||||
|
||||
static void node_composit_init_blur(bNode* node)
|
||||
|
||||
@@ -143,7 +143,7 @@ static float RI_vdC(unsigned int bits, unsigned int r)
|
||||
// single channel IIR gaussian filtering
|
||||
// much faster than anything else, constant time independent of width
|
||||
// should extend to multichannel and make this a node, could be useful
|
||||
static void IIR_gauss(CompBuf* buf, float sigma)
|
||||
static void IIR_gauss_single(CompBuf* buf, float sigma)
|
||||
{
|
||||
double q, q2, sc, cf[4], tsM[9], tsu[3], tsv[3];
|
||||
float *X, *Y, *W;
|
||||
@@ -322,8 +322,8 @@ static void defocus_blur(bNode *node, CompBuf *new, CompBuf *img, CompBuf *zbuf,
|
||||
// bug #6656 part 1, probably when previous node_composite.c was split into separate files, it was not properly updated
|
||||
// to include recent cvs commits (well, at least not defocus node), so this part was missing...
|
||||
wt = aperture*128.f;
|
||||
IIR_gauss(crad, wt);
|
||||
IIR_gauss(wts, wt);
|
||||
IIR_gauss_single(crad, wt);
|
||||
IIR_gauss_single(wts, wt);
|
||||
|
||||
// bug #6656 part 2a, although foreground blur is not based anymore on closest object,
|
||||
// the rescaling op below was still based on that anyway, and unlike the comment in below code,
|
||||
|
||||
498
source/blender/nodes/intern/CMP_nodes/CMP_glare.c
Normal file
498
source/blender/nodes/intern/CMP_nodes/CMP_glare.c
Normal file
@@ -0,0 +1,498 @@
|
||||
/**
|
||||
*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2006 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Alfredo de Greef (eeshlo)
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "../CMP_util.h"
|
||||
|
||||
static bNodeSocketType cmp_node_glare_in[]= {
|
||||
{ SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
|
||||
{ -1, 0, "" }
|
||||
};
|
||||
static bNodeSocketType cmp_node_glare_out[]= {
|
||||
{ SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
||||
{ -1, 0, "" }
|
||||
};
|
||||
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// adds src to dst image, must be of same size
|
||||
static void addImage(CompBuf* dst, CompBuf* src, float scale)
|
||||
{
|
||||
if ((dst->x == src->x) && (dst->y == src->y)) {
|
||||
int p = dst->x*dst->y*dst->type;
|
||||
float *dcol = dst->rect, *scol = src->rect;
|
||||
while (p--) *dcol++ += *scol++ * scale;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// returns possibly downscaled copy of all pixels above threshold
|
||||
static CompBuf* BTP(CompBuf* src, float threshold, int scaledown)
|
||||
{
|
||||
int x, y;
|
||||
CompBuf* bsrc = qd_downScaledCopy(src, scaledown);
|
||||
float* cr = bsrc->rect;
|
||||
for (y=0; y<bsrc->y; ++y)
|
||||
for (x=0; x<bsrc->x; ++x, cr+=4) {
|
||||
if ((0.212671f*cr[0] + 0.71516f*cr[1] + 0.072169f*cr[2]) >= threshold) {
|
||||
cr[0] -= threshold, cr[1] -= threshold, cr[2] -= threshold;
|
||||
cr[0] = MAX2(cr[0], 0.f);
|
||||
cr[1] = MAX2(cr[1], 0.f);
|
||||
cr[2] = MAX2(cr[2], 0.f);
|
||||
}
|
||||
else cr[0] = cr[1] = cr[2] = 0.f;
|
||||
}
|
||||
return bsrc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// simple 4-point star filter
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// streak filter
|
||||
|
||||
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 = cosf(an), vy = sinf(an);
|
||||
for (n=0; n<ndg->iter; ++n) {
|
||||
const float p4 = powf(4.f, n);
|
||||
const float vxp = vx*p4, vyp = vy*p4;
|
||||
const float wt = powf(ndg->fade, p4);
|
||||
const float cmo = 1.f - powf(ndg->colmod, 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);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// Ghosts (lensflare)
|
||||
|
||||
static float smoothMask(float x, float y)
|
||||
{
|
||||
float t;
|
||||
x = 2.f*x - 1.f, y = 2.f*y - 1.f;
|
||||
if ((t = 1.f - sqrtf(x*x + y*y)) <= 0.f) return 0.f;
|
||||
return t;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// Fog glow (convolution with kernel of exponential falloff)
|
||||
|
||||
static void fglow(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
|
||||
{
|
||||
int x, y;
|
||||
float scale, u, v, r, w, d;
|
||||
fRGB fcol;
|
||||
CompBuf *tsrc, *ckrn;
|
||||
unsigned int sz = 1 << ndg->size;
|
||||
const float cs_r = 1.f, cs_g = 1.f, cs_b = 1.f;
|
||||
|
||||
// temp. src image
|
||||
tsrc = BTP(src, ndg->threshold, 1 << ndg->quality);
|
||||
// make the convolution kernel
|
||||
ckrn = alloc_compbuf(sz, sz, CB_RGBA, 1);
|
||||
|
||||
scale = 0.25f*sqrtf(sz*sz);
|
||||
|
||||
for (y=0; y<sz; ++y) {
|
||||
v = 2.f*(y / (float)sz) - 1.f;
|
||||
for (x=0; x<sz; ++x) {
|
||||
u = 2.f*(x / (float)sz) - 1.f;
|
||||
r = (u*u + v*v)*scale;
|
||||
d = -sqrtf(sqrtf(sqrtf(r)))*9.f;
|
||||
fcol[0] = expf(d*cs_r), fcol[1] = expf(d*cs_g), fcol[2] = expf(d*cs_b);
|
||||
// linear window good enough here, visual result counts, not scientific analysis
|
||||
//w = (1.f-fabs(u))*(1.f-fabs(v));
|
||||
// actually, Hanning window is ok, cos^2 for some reason is slower
|
||||
w = (0.5f + 0.5f*cosf(u*(float)M_PI))*(0.5f + 0.5f*cosf(v*(float)M_PI));
|
||||
fRGB_mult(fcol, w);
|
||||
qd_setPixel(ckrn, x, y, fcol);
|
||||
}
|
||||
}
|
||||
|
||||
convolve(tsrc, tsrc, ckrn);
|
||||
free_compbuf(ckrn);
|
||||
mixImages(dst, tsrc, 0.5f + 0.5f*ndg->mix);
|
||||
free_compbuf(tsrc);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
|
||||
static void node_composit_exec_glare(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
||||
{
|
||||
CompBuf *new, *img = in[0]->data;
|
||||
NodeGlare* ndg = node->storage;
|
||||
|
||||
if ((img == NULL) || (out[0]->hasoutput == 0)) return;
|
||||
|
||||
if (img->type != CB_RGBA)
|
||||
new = typecheck_compbuf(img, CB_RGBA);
|
||||
else
|
||||
new = dupalloc_compbuf(img);
|
||||
|
||||
{
|
||||
int x, y;
|
||||
for (y=0; y<new->y; ++y) {
|
||||
fRGB* col = (fRGB*)&new->rect[y*new->x*new->type];
|
||||
for (x=0; x<new->x; ++x) {
|
||||
col[x][0] = MAX2(col[x][0], 0.f);
|
||||
col[x][1] = MAX2(col[x][1], 0.f);
|
||||
col[x][2] = MAX2(col[x][2], 0.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (ndg->type) {
|
||||
case 0:
|
||||
star4(ndg, new, img);
|
||||
break;
|
||||
case 1:
|
||||
fglow(ndg, new, img);
|
||||
break;
|
||||
case 3:
|
||||
ghosts(ndg, new, img);
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
streaks(ndg, new, img);
|
||||
}
|
||||
|
||||
out[0]->data = new;
|
||||
}
|
||||
|
||||
static void node_composit_init_glare(bNode* node)
|
||||
{
|
||||
NodeGlare *ndg = MEM_callocN(sizeof(NodeGlare), "node glare data");
|
||||
ndg->quality = 1;
|
||||
ndg->type = 2;
|
||||
ndg->iter = 3;
|
||||
ndg->colmod = 0.25;
|
||||
ndg->mix = 0;
|
||||
ndg->threshold = 1;
|
||||
ndg->angle = 4;
|
||||
ndg->angle_ofs = 0;
|
||||
ndg->fade = 0.9;
|
||||
ndg->size = 8;
|
||||
node->storage = ndg;
|
||||
}
|
||||
|
||||
bNodeType cmp_node_glare = {
|
||||
/* *next,*prev */ NULL, NULL,
|
||||
/* type code */ CMP_NODE_GLARE,
|
||||
/* name */ "Glare",
|
||||
/* width+range */ 150, 120, 200,
|
||||
/* class+opts */ NODE_CLASS_OP_FILTER, NODE_OPTIONS,
|
||||
/* input sock */ cmp_node_glare_in,
|
||||
/* output sock */ cmp_node_glare_out,
|
||||
/* storage */ "NodeGlare",
|
||||
/* execfunc */ node_composit_exec_glare,
|
||||
/* butfunc */ NULL,
|
||||
/* initfunc */ node_composit_init_glare,
|
||||
/* freestoragefunc */ node_free_standard_storage,
|
||||
/* copystoragefunc */ node_copy_standard_storage,
|
||||
/* id */ NULL
|
||||
};
|
||||
192
source/blender/nodes/intern/CMP_nodes/CMP_lensdist.c
Normal file
192
source/blender/nodes/intern/CMP_nodes/CMP_lensdist.c
Normal file
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2006 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Alfredo de Greef (eeshlo)
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "../CMP_util.h"
|
||||
|
||||
static bNodeSocketType cmp_node_lensdist_in[]= {
|
||||
{ SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
|
||||
{ SOCK_VALUE, 1, "Distort", 0.f, 0.f, 0.f, 0.f, -0.999f, 1.f},
|
||||
{ SOCK_VALUE, 1, "Dispersion", 0.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
||||
{ -1, 0, "" }
|
||||
};
|
||||
static bNodeSocketType cmp_node_lensdist_out[]= {
|
||||
{ SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
||||
{ -1, 0, "" }
|
||||
};
|
||||
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void node_composit_exec_lensdist(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
||||
{
|
||||
CompBuf *new, *img = in[0]->data;
|
||||
NodeLensDist* nld = node->storage;
|
||||
const float k = MAX2(MIN2(in[1]->vec[0], 1.f), -0.999f);
|
||||
// smaller dispersion range for somewhat more control
|
||||
const float d = 0.25f*MAX2(MIN2(in[2]->vec[0], 1.f), 0.f);
|
||||
const float kr = MAX2(MIN2((k+d), 1.f), -0.999f), kb = MAX2(MIN2((k-d), 1.f), -0.999f);
|
||||
|
||||
if ((img==NULL) || (out[0]->hasoutput==0)) return;
|
||||
|
||||
new = alloc_compbuf(img->x, img->y, CB_RGBA, 1);
|
||||
|
||||
lensDistort(new, img, (nld->proj ? d : kr), k, kb, nld->jit, nld->proj, nld->fit);
|
||||
|
||||
out[0]->data = new;
|
||||
}
|
||||
|
||||
|
||||
static void node_composit_init_lensdist(bNode* node)
|
||||
{
|
||||
NodeLensDist *nld = MEM_callocN(sizeof(NodeLensDist), "node lensdist data");
|
||||
nld->jit = nld->proj = nld->fit = 0;
|
||||
node->storage = nld;
|
||||
}
|
||||
|
||||
|
||||
bNodeType cmp_node_lensdist = {
|
||||
/* *next,*prev */ NULL, NULL,
|
||||
/* type code */ CMP_NODE_LENSDIST,
|
||||
/* name */ "Lens Distortion",
|
||||
/* width+range */ 150, 120, 200,
|
||||
/* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS,
|
||||
/* input sock */ cmp_node_lensdist_in,
|
||||
/* output sock */ cmp_node_lensdist_out,
|
||||
/* storage */ "NodeLensDist",
|
||||
/* execfunc */ node_composit_exec_lensdist,
|
||||
/* butfunc */ NULL,
|
||||
/* initfunc */ node_composit_init_lensdist,
|
||||
/* freestoragefunc */ node_free_standard_storage,
|
||||
/* copystoragefunc */ node_copy_standard_storage,
|
||||
/* id */ NULL
|
||||
};
|
||||
173
source/blender/nodes/intern/CMP_nodes/CMP_tonemap.c
Normal file
173
source/blender/nodes/intern/CMP_nodes/CMP_tonemap.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2006 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Alfredo de Greef (eeshlo)
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "../CMP_util.h"
|
||||
|
||||
static bNodeSocketType cmp_node_tonemap_in[]= {
|
||||
{ SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
|
||||
{ -1, 0, "" }
|
||||
};
|
||||
static bNodeSocketType cmp_node_tonemap_out[]= {
|
||||
{ SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
||||
{ -1, 0, "" }
|
||||
};
|
||||
|
||||
|
||||
static float avgLogLum(CompBuf *src, float* auto_key, float* Lav, float* Cav)
|
||||
{
|
||||
float lsum = 0;
|
||||
int p = src->x*src->y;
|
||||
fRGB* bc = (fRGB*)src->rect;
|
||||
float avl, maxl = -1e10f, minl = 1e10f;
|
||||
const float sc = 1.f/(src->x*src->y);
|
||||
*Lav = 0.f;
|
||||
while (p--) {
|
||||
float L = 0.212671f*bc[0][0] + 0.71516f*bc[0][1] + 0.072169f*bc[0][2];
|
||||
*Lav += L;
|
||||
fRGB_add(Cav, bc[0]);
|
||||
lsum += logf(MAX2(L, 0.f) + 1e-5f);
|
||||
maxl = (L > maxl) ? L : maxl;
|
||||
minl = (L < minl) ? L : minl;
|
||||
bc++;
|
||||
}
|
||||
*Lav *= sc;
|
||||
fRGB_mult(Cav, sc);
|
||||
maxl = logf(maxl + 1e-5f), minl = logf(minl + 1e-5f), avl = lsum*sc;
|
||||
*auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.f;
|
||||
return expf(avl);
|
||||
}
|
||||
|
||||
|
||||
void static tonemap(NodeTonemap* ntm, CompBuf* dst, CompBuf* src)
|
||||
{
|
||||
int x, y;
|
||||
float dr, dg, db, al, igm = (ntm->gamma==0.f) ? 1 : (1.f / ntm->gamma);
|
||||
float auto_key, Lav, Cav[3] = {0, 0, 0};
|
||||
|
||||
al = avgLogLum(src, &auto_key, &Lav, Cav);
|
||||
al = (al == 0.f) ? 0.f : (ntm->key / al);
|
||||
|
||||
if (ntm->type == 1) {
|
||||
// Reinhard/Devlin photoreceptor
|
||||
const float f = expf(-ntm->f);
|
||||
const float m = (ntm->m > 0.f) ? ntm->m : (0.3f + 0.7f*powf(auto_key, 1.4f));
|
||||
const float ic = 1.f - ntm->c, ia = 1.f - ntm->a;
|
||||
if (ntm->m == 0.f) printf("tonemap node, M: %g\n", m);
|
||||
for (y=0; y<src->y; ++y) {
|
||||
fRGB* sp = (fRGB*)&src->rect[y*src->x*src->type];
|
||||
fRGB* dp = (fRGB*)&dst->rect[y*src->x*src->type];
|
||||
for (x=0; x<src->x; ++x) {
|
||||
const float L = 0.212671f*sp[x][0] + 0.71516f*sp[x][1] + 0.072169f*sp[x][2];
|
||||
float I_l = sp[x][0] + ic*(L - sp[x][0]);
|
||||
float I_g = Cav[0] + ic*(Lav - Cav[0]);
|
||||
float I_a = I_l + ia*(I_g - I_l);
|
||||
dp[x][0] /= (dp[x][0] + powf(f*I_a, m));
|
||||
I_l = sp[x][1] + ic*(L - sp[x][1]);
|
||||
I_g = Cav[1] + ic*(Lav - Cav[1]);
|
||||
I_a = I_l + ia*(I_g - I_l);
|
||||
dp[x][1] /= (dp[x][1] + powf(f*I_a, m));
|
||||
I_l = sp[x][2] + ic*(L - sp[x][2]);
|
||||
I_g = Cav[2] + ic*(Lav - Cav[2]);
|
||||
I_a = I_l + ia*(I_g - I_l);
|
||||
dp[x][2] /= (dp[x][2] + powf(f*I_a, m));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Reinhard simple photographic tm (simplest, not using whitepoint var)
|
||||
for (y=0; y<src->y; y++) {
|
||||
fRGB* sp = (fRGB*)&src->rect[y*src->x*src->type];
|
||||
fRGB* dp = (fRGB*)&dst->rect[y*src->x*src->type];
|
||||
for (x=0; x<src->x; x++) {
|
||||
fRGB_copy(dp[x], sp[x]);
|
||||
fRGB_mult(dp[x], al);
|
||||
dr = dp[x][0] + ntm->offset;
|
||||
dg = dp[x][1] + ntm->offset;
|
||||
db = dp[x][2] + ntm->offset;
|
||||
dp[x][0] /= ((dr == 0.f) ? 1.f : dr);
|
||||
dp[x][1] /= ((dg == 0.f) ? 1.f : dg);
|
||||
dp[x][2] /= ((db == 0.f) ? 1.f : db);
|
||||
if (igm != 0.f) {
|
||||
dp[x][0] = powf(MAX2(dp[x][0], 0.f), igm);
|
||||
dp[x][1] = powf(MAX2(dp[x][1], 0.f), igm);
|
||||
dp[x][2] = powf(MAX2(dp[x][2], 0.f), igm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void node_composit_exec_tonemap(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
||||
{
|
||||
CompBuf *new, *img = in[0]->data;
|
||||
|
||||
if ((img==NULL) || (out[0]->hasoutput==0)) return;
|
||||
|
||||
if (img->type != CB_RGBA)
|
||||
new = typecheck_compbuf(img, CB_RGBA);
|
||||
else
|
||||
new = dupalloc_compbuf(img);
|
||||
|
||||
tonemap(node->storage, new, img);
|
||||
|
||||
out[0]->data = new;
|
||||
}
|
||||
|
||||
static void node_composit_init_tonemap(bNode* node)
|
||||
{
|
||||
NodeTonemap *ntm = MEM_callocN(sizeof(NodeTonemap), "node tonemap data");
|
||||
ntm->type = 1;
|
||||
ntm->key = 0.18;
|
||||
ntm->offset = 1;
|
||||
ntm->gamma = 1;
|
||||
ntm->f = 0;
|
||||
ntm->m = 0; // actual value is set according to input
|
||||
// default a of 1 works well with natural HDR images, but not always so for cgi.
|
||||
// Maybe should use 0 or at least lower initial value instead
|
||||
ntm->a = 1;
|
||||
ntm->c = 0;
|
||||
node->storage = ntm;
|
||||
}
|
||||
|
||||
bNodeType cmp_node_tonemap = {
|
||||
/* *next,*prev */ NULL, NULL,
|
||||
/* type code */ CMP_NODE_TONEMAP,
|
||||
/* name */ "Tonemap",
|
||||
/* width+range */ 150, 120, 200,
|
||||
/* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
|
||||
/* input sock */ cmp_node_tonemap_in,
|
||||
/* output sock */ cmp_node_tonemap_out,
|
||||
/* storage */ "NodeTonemap",
|
||||
/* execfunc */ node_composit_exec_tonemap,
|
||||
/* butfunc */ NULL,
|
||||
/* initfunc */ node_composit_init_tonemap,
|
||||
/* freestoragefunc */ node_free_standard_storage,
|
||||
/* copystoragefunc */ node_copy_standard_storage,
|
||||
/* id */ NULL
|
||||
};
|
||||
@@ -29,9 +29,6 @@
|
||||
|
||||
#include "CMP_util.h"
|
||||
|
||||
|
||||
|
||||
|
||||
CompBuf *alloc_compbuf(int sizex, int sizey, int type, int alloc)
|
||||
{
|
||||
CompBuf *cbuf= MEM_callocN(sizeof(CompBuf), "compbuf");
|
||||
@@ -577,3 +574,593 @@ void gamma_correct_compbuf(CompBuf *img, int inversed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* 2D Fast Hartley Transform, used for convolution
|
||||
*/
|
||||
|
||||
typedef float fREAL;
|
||||
|
||||
// returns next highest power of 2 of x, as well it's log2 in L2
|
||||
static unsigned int nextPow2(unsigned int x, unsigned int* L2)
|
||||
{
|
||||
unsigned int pw, x_notpow2 = x & (x-1);
|
||||
*L2 = 0;
|
||||
while (x>>=1) ++(*L2);
|
||||
pw = 1 << (*L2);
|
||||
if (x_notpow2) { (*L2)++; pw<<=1; }
|
||||
return pw;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// from FXT library by Joerg Arndt, faster in order bitreversal
|
||||
// use: r = revbin_upd(r, h) where h = N>>1
|
||||
static unsigned int revbin_upd(unsigned int r, unsigned int h)
|
||||
{
|
||||
while (!((r^=h)&h)) h >>= 1;
|
||||
return r;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
static void FHT(fREAL* data, unsigned int M, unsigned int inverse)
|
||||
{
|
||||
double tt, fc, dc, fs, ds, a = M_PI;
|
||||
fREAL t1, t2;
|
||||
int n2, bd, bl, istep, k, len = 1 << M, n = 1;
|
||||
|
||||
int i, j = 0;
|
||||
unsigned int Nh = len >> 1;
|
||||
for (i=1;i<(len-1);++i) {
|
||||
j = revbin_upd(j, Nh);
|
||||
if (j>i) {
|
||||
t1 = data[i];
|
||||
data[i] = data[j];
|
||||
data[j] = t1;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
fREAL* data_n = &data[n];
|
||||
|
||||
istep = n << 1;
|
||||
for (k=0; k<len; k+=istep) {
|
||||
t1 = data_n[k];
|
||||
data_n[k] = data[k] - t1;
|
||||
data[k] += t1;
|
||||
}
|
||||
|
||||
n2 = n >> 1;
|
||||
if (n>2) {
|
||||
fc = dc = cos(a);
|
||||
fs = ds = sqrt(1.0 - fc*fc); //sin(a);
|
||||
bd = n-2;
|
||||
for (bl=1; bl<n2; bl++) {
|
||||
fREAL* data_nbd = &data_n[bd];
|
||||
fREAL* data_bd = &data[bd];
|
||||
for (k=bl; k<len; k+=istep) {
|
||||
t1 = fc*data_n[k] + fs*data_nbd[k];
|
||||
t2 = fs*data_n[k] - fc*data_nbd[k];
|
||||
data_n[k] = data[k] - t1;
|
||||
data_nbd[k] = data_bd[k] - t2;
|
||||
data[k] += t1;
|
||||
data_bd[k] += t2;
|
||||
}
|
||||
tt = fc*dc - fs*ds;
|
||||
fs = fs*dc + fc*ds;
|
||||
fc = tt;
|
||||
bd -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (n>1) {
|
||||
for (k=n2; k<len; k+=istep) {
|
||||
t1 = data_n[k];
|
||||
data_n[k] = data[k] - t1;
|
||||
data[k] += t1;
|
||||
}
|
||||
}
|
||||
|
||||
n = istep;
|
||||
a *= 0.5;
|
||||
} while (n<len);
|
||||
|
||||
if (inverse) {
|
||||
fREAL sc = (fREAL)1 / (fREAL)len;
|
||||
for (k=0; k<len; ++k)
|
||||
data[k] *= sc;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/* 2D Fast Hartley Transform, Mx/My -> log2 of width/height,
|
||||
nzp -> the row where zero pad data starts,
|
||||
inverse -> see above */
|
||||
static void FHT2D(fREAL *data, unsigned int Mx, unsigned int My,
|
||||
unsigned int nzp, unsigned int inverse)
|
||||
{
|
||||
unsigned int i, j, Nx, Ny, maxy;
|
||||
fREAL t;
|
||||
|
||||
Nx = 1 << Mx;
|
||||
Ny = 1 << My;
|
||||
|
||||
// rows (forward transform skips 0 pad data)
|
||||
maxy = inverse ? Ny : nzp;
|
||||
for (j=0; j<maxy; ++j)
|
||||
FHT(&data[Nx*j], Mx, inverse);
|
||||
|
||||
// transpose data
|
||||
if (Nx==Ny) { // square
|
||||
for (j=0; j<Ny; ++j)
|
||||
for (i=j+1; i<Nx; ++i) {
|
||||
unsigned int op = i + (j << Mx), np = j + (i << My);
|
||||
t=data[op], data[op]=data[np], data[np]=t;
|
||||
}
|
||||
}
|
||||
else { // rectangular
|
||||
unsigned int k, Nym = Ny-1, stm = 1 << (Mx + My);
|
||||
for (i=0; stm>0; i++) {
|
||||
#define pred(k) (((k & Nym) << Mx) + (k >> My))
|
||||
for (j=pred(i); j>i; j=pred(j));
|
||||
if (j < i) continue;
|
||||
for (k=i, j=pred(i); j!=i; k=j, j=pred(j), stm--)
|
||||
{ t=data[j], data[j]=data[k], data[k]=t; }
|
||||
#undef pred
|
||||
stm--;
|
||||
}
|
||||
}
|
||||
// swap Mx/My & Nx/Ny
|
||||
i = Nx, Nx = Ny, Ny = i;
|
||||
i = Mx, Mx = My, My = i;
|
||||
|
||||
// now columns == transposed rows
|
||||
for (j=0; j<Ny; ++j)
|
||||
FHT(&data[Nx*j], Mx, inverse);
|
||||
|
||||
// finalize
|
||||
for (j=0; j<=(Ny >> 1); j++) {
|
||||
unsigned int jm = (Ny - j) & (Ny-1);
|
||||
unsigned int ji = j << Mx;
|
||||
unsigned int jmi = jm << Mx;
|
||||
for (i=0; i<=(Nx >> 1); i++) {
|
||||
unsigned int im = (Nx - i) & (Nx-1);
|
||||
fREAL A = data[ji + i];
|
||||
fREAL B = data[jmi + i];
|
||||
fREAL C = data[ji + im];
|
||||
fREAL D = data[jmi + im];
|
||||
fREAL E = (fREAL)0.5*((A + D) - (B + C));
|
||||
data[ji + i] = A - E;
|
||||
data[jmi + i] = B + E;
|
||||
data[ji + im] = C + E;
|
||||
data[jmi + im] = D - E;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/* 2D convolution calc, d1 *= d2, M/N - > log2 of width/height */
|
||||
static void fht_convolve(fREAL* d1, fREAL* d2, unsigned int M, unsigned int N)
|
||||
{
|
||||
fREAL a, b;
|
||||
unsigned int i, j, k, L, mj, mL;
|
||||
unsigned int m = 1 << M, n = 1 << N;
|
||||
unsigned int m2 = 1 << (M-1), n2 = 1 << (N-1);
|
||||
unsigned int mn2 = m << (N-1);
|
||||
|
||||
d1[0] *= d2[0];
|
||||
d1[mn2] *= d2[mn2];
|
||||
d1[m2] *= d2[m2];
|
||||
d1[m2 + mn2] *= d2[m2 + mn2];
|
||||
for (i=1; i<m2; i++) {
|
||||
k = m - i;
|
||||
a = d1[i]*d2[i] - d1[k]*d2[k];
|
||||
b = d1[k]*d2[i] + d1[i]*d2[k];
|
||||
d1[i] = (b + a)*(fREAL)0.5;
|
||||
d1[k] = (b - a)*(fREAL)0.5;
|
||||
a = d1[i + mn2]*d2[i + mn2] - d1[k + mn2]*d2[k + mn2];
|
||||
b = d1[k + mn2]*d2[i + mn2] + d1[i + mn2]*d2[k + mn2];
|
||||
d1[i + mn2] = (b + a)*(fREAL)0.5;
|
||||
d1[k + mn2] = (b - a)*(fREAL)0.5;
|
||||
}
|
||||
for (j=1; j<n2; j++) {
|
||||
L = n - j;
|
||||
mj = j << M;
|
||||
mL = L << M;
|
||||
a = d1[mj]*d2[mj] - d1[mL]*d2[mL];
|
||||
b = d1[mL]*d2[mj] + d1[mj]*d2[mL];
|
||||
d1[mj] = (b + a)*(fREAL)0.5;
|
||||
d1[mL] = (b - a)*(fREAL)0.5;
|
||||
a = d1[m2 + mj]*d2[m2 + mj] - d1[m2 + mL]*d2[m2 + mL];
|
||||
b = d1[m2 + mL]*d2[m2 + mj] + d1[m2 + mj]*d2[m2 + mL];
|
||||
d1[m2 + mj] = (b + a)*(fREAL)0.5;
|
||||
d1[m2 + mL] = (b - a)*(fREAL)0.5;
|
||||
}
|
||||
for (i=1; i<m2; i++) {
|
||||
k = m - i;
|
||||
for (j=1; j<n2; j++) {
|
||||
L = n - j;
|
||||
mj = j << M;
|
||||
mL = L << M;
|
||||
a = d1[i + mj]*d2[i + mj] - d1[k + mL]*d2[k + mL];
|
||||
b = d1[k + mL]*d2[i + mj] + d1[i + mj]*d2[k + mL];
|
||||
d1[i + mj] = (b + a)*(fREAL)0.5;
|
||||
d1[k + mL] = (b - a)*(fREAL)0.5;
|
||||
a = d1[i + mL]*d2[i + mL] - d1[k + mj]*d2[k + mj];
|
||||
b = d1[k + mj]*d2[i + mL] + d1[i + mL]*d2[k + mj];
|
||||
d1[i + mL] = (b + a)*(fREAL)0.5;
|
||||
d1[k + mj] = (b - a)*(fREAL)0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void convolve(CompBuf* dst, CompBuf* in1, CompBuf* in2)
|
||||
{
|
||||
fREAL *data1, *data2, *fp;
|
||||
unsigned int w2, h2, hw, hh, log2_w, log2_h;
|
||||
fRGB wt, *colp;
|
||||
int x, y, ch;
|
||||
int xbl, ybl, nxb, nyb, xbsz, ybsz;
|
||||
int in2done = 0;
|
||||
|
||||
CompBuf* rdst = alloc_compbuf(in1->x, in1->y, in1->type, 1);
|
||||
|
||||
// convolution result width & height
|
||||
w2 = 2*in2->x - 1;
|
||||
h2 = 2*in2->y - 1;
|
||||
// FFT pow2 required size & log2
|
||||
w2 = nextPow2(w2, &log2_w);
|
||||
h2 = nextPow2(h2, &log2_h);
|
||||
|
||||
// alloc space
|
||||
data1 = (fREAL*)MEM_callocN(3*w2*h2*sizeof(fREAL), "convolve_fast FHT data1");
|
||||
data2 = (fREAL*)MEM_callocN(w2*h2*sizeof(fREAL), "convolve_fast FHT data2");
|
||||
|
||||
// normalize convolutor
|
||||
wt[0] = wt[1] = wt[2] = 0.f;
|
||||
for (y=0; y<in2->y; y++) {
|
||||
colp = (fRGB*)&in2->rect[y*in2->x*in2->type];
|
||||
for (x=0; x<in2->x; x++)
|
||||
fRGB_add(wt, colp[x]);
|
||||
}
|
||||
if (wt[0] != 0.f) wt[0] = 1.f/wt[0];
|
||||
if (wt[1] != 0.f) wt[1] = 1.f/wt[1];
|
||||
if (wt[2] != 0.f) wt[2] = 1.f/wt[2];
|
||||
for (y=0; y<in2->y; y++) {
|
||||
colp = (fRGB*)&in2->rect[y*in2->x*in2->type];
|
||||
for (x=0; x<in2->x; x++)
|
||||
fRGB_colormult(colp[x], wt);
|
||||
}
|
||||
|
||||
// copy image data, unpacking interleaved RGBA into separate channels
|
||||
// only need to calc data1 once
|
||||
|
||||
// block add-overlap
|
||||
hw = in2->x >> 1;
|
||||
hh = in2->y >> 1;
|
||||
xbsz = (w2 + 1) - in2->x;
|
||||
ybsz = (h2 + 1) - in2->y;
|
||||
nxb = in1->x / xbsz;
|
||||
if (in1->x % xbsz) nxb++;
|
||||
nyb = in1->y / ybsz;
|
||||
if (in1->y % ybsz) nyb++;
|
||||
for (ybl=0; ybl<nyb; ybl++) {
|
||||
for (xbl=0; xbl<nxb; xbl++) {
|
||||
|
||||
// each channel one by one
|
||||
for (ch=0; ch<3; ch++) {
|
||||
fREAL* data1ch = &data1[ch*w2*h2];
|
||||
|
||||
// only need to calc fht data from in2 once, can re-use for every block
|
||||
if (!in2done) {
|
||||
// in2, channel ch -> data1
|
||||
for (y=0; y<in2->y; y++) {
|
||||
fp = &data1ch[y*w2];
|
||||
colp = (fRGB*)&in2->rect[y*in2->x*in2->type];
|
||||
for (x=0; x<in2->x; x++)
|
||||
fp[x] = colp[x][ch];
|
||||
}
|
||||
}
|
||||
|
||||
// in1, channel ch -> data2
|
||||
memset(data2, 0, w2*h2*sizeof(fREAL));
|
||||
for (y=0; y<ybsz; y++) {
|
||||
int yy = ybl*ybsz + y;
|
||||
if (yy >= in1->y) continue;
|
||||
fp = &data2[y*w2];
|
||||
colp = (fRGB*)&in1->rect[yy*in1->x*in1->type];
|
||||
for (x=0; x<xbsz; x++) {
|
||||
int xx = xbl*xbsz + x;
|
||||
if (xx >= in1->x) continue;
|
||||
fp[x] = colp[xx][ch];
|
||||
}
|
||||
}
|
||||
|
||||
// forward FHT
|
||||
// zero pad data start is different for each == height+1
|
||||
if (!in2done) FHT2D(data1ch, log2_w, log2_h, in2->y+1, 0);
|
||||
FHT2D(data2, log2_w, log2_h, in2->y+1, 0);
|
||||
|
||||
// FHT2D transposed data, row/col now swapped
|
||||
// convolve & inverse FHT
|
||||
fht_convolve(data2, data1ch, log2_h, log2_w);
|
||||
FHT2D(data2, log2_h, log2_w, 0, 1);
|
||||
// data again transposed, so in order again
|
||||
|
||||
// overlap-add result
|
||||
for (y=0; y<(int)h2; y++) {
|
||||
const int yy = ybl*ybsz + y - hh;
|
||||
if ((yy < 0) || (yy >= in1->y)) continue;
|
||||
fp = &data2[y*w2];
|
||||
colp = (fRGB*)&rdst->rect[yy*in1->x*in1->type];
|
||||
for (x=0; x<(int)w2; x++) {
|
||||
const int xx = xbl*xbsz + x - hw;
|
||||
if ((xx < 0) || (xx >= in1->x)) continue;
|
||||
colp[xx][ch] += fp[x];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
in2done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(data2);
|
||||
MEM_freeN(data1);
|
||||
memcpy(dst->rect, rdst->rect, sizeof(float)*dst->x*dst->y*dst->type);
|
||||
free_compbuf(rdst);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Utility functions qd_* should probably be intergrated better with other functions here.
|
||||
*
|
||||
*/
|
||||
// sets fcol to pixelcolor at (x, y)
|
||||
void qd_getPixel(CompBuf* src, int x, int y, float* col)
|
||||
{
|
||||
if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) {
|
||||
float* bc = &src->rect[(x + y*src->x)*src->type];
|
||||
col[0] = bc[0], col[1] = bc[1], col[2] = bc[2];
|
||||
}
|
||||
else col[0] = col[1] = col[2] = 0.f;
|
||||
}
|
||||
|
||||
// sets pixel (x, y) to color col
|
||||
void qd_setPixel(CompBuf* src, int x, int y, float* col)
|
||||
{
|
||||
if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) {
|
||||
float* bc = &src->rect[(x + y*src->x)*src->type];
|
||||
bc[0] = col[0], bc[1] = col[1], bc[2] = col[2];
|
||||
}
|
||||
}
|
||||
|
||||
// adds fcol to pixelcolor (x, y)
|
||||
void qd_addPixel(CompBuf* src, int x, int y, float* col)
|
||||
{
|
||||
if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) {
|
||||
float* bc = &src->rect[(x + y*src->x)*src->type];
|
||||
bc[0] += col[0], bc[1] += col[1], bc[2] += col[2];
|
||||
}
|
||||
}
|
||||
|
||||
// multiplies pixel by factor value f
|
||||
void qd_multPixel(CompBuf* src, int x, int y, float f)
|
||||
{
|
||||
if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) {
|
||||
float* bc = &src->rect[(x + y*src->x)*src->type];
|
||||
bc[0] *= f, bc[1] *= f, bc[2] *= f;
|
||||
}
|
||||
}
|
||||
|
||||
// bilinear interpolation with wraparound
|
||||
void qd_getPixelLerpWrap(CompBuf* src, float u, float v, float* col)
|
||||
{
|
||||
const float ufl = floorf(u), vfl = floorf(v);
|
||||
const int nx = (int)ufl % src->x, ny = (int)vfl % src->y;
|
||||
const int x1 = (nx < 0) ? (nx + src->x) : nx;
|
||||
const int y1 = (ny < 0) ? (ny + src->y) : ny;
|
||||
const int x2 = (x1 + 1) % src->x, y2 = (y1 + 1) % src->y;
|
||||
const float* c00 = &src->rect[(x1 + y1*src->x)*src->type];
|
||||
const float* c10 = &src->rect[(x2 + y1*src->x)*src->type];
|
||||
const float* c01 = &src->rect[(x1 + y2*src->x)*src->type];
|
||||
const float* c11 = &src->rect[(x2 + y2*src->x)*src->type];
|
||||
const float uf = u - ufl, vf = v - vfl;
|
||||
const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf;
|
||||
col[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0];
|
||||
if (src->type != CB_VAL) {
|
||||
col[1] = w00*c00[1] + w10*c10[1] + w01*c01[1] + w11*c11[1];
|
||||
col[2] = w00*c00[2] + w10*c10[2] + w01*c01[2] + w11*c11[2];
|
||||
col[3] = w00*c00[3] + w10*c10[3] + w01*c01[3] + w11*c11[3];
|
||||
}
|
||||
}
|
||||
|
||||
// as above, without wrap around
|
||||
void qd_getPixelLerp(CompBuf* src, float u, float v, float* col)
|
||||
{
|
||||
const float ufl = floorf(u), vfl = floorf(v);
|
||||
const int x1 = (int)ufl, y1 = (int)vfl;
|
||||
const int x2 = (int)ceilf(u), y2 = (int)ceilf(v);
|
||||
if ((x2 >= 0) && (y2 >= 0) && (x1 < src->x) && (y1 < src->y)) {
|
||||
const float B[4] = {0,0,0,0};
|
||||
const int ox1 = (x1 < 0), oy1 = (y1 < 0), ox2 = (x2 >= src->x), oy2 = (y2 >= src->y);
|
||||
const float* c00 = (ox1 || oy1) ? B : &src->rect[(x1 + y1*src->x)*src->type];
|
||||
const float* c10 = (ox2 || oy1) ? B : &src->rect[(x2 + y1*src->x)*src->type];
|
||||
const float* c01 = (ox1 || oy2) ? B : &src->rect[(x1 + y2*src->x)*src->type];
|
||||
const float* c11 = (ox2 || oy2) ? B : &src->rect[(x2 + y2*src->x)*src->type];
|
||||
const float uf = u - ufl, vf = v - vfl;
|
||||
const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf;
|
||||
col[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0];
|
||||
if (src->type != CB_VAL) {
|
||||
col[1] = w00*c00[1] + w10*c10[1] + w01*c01[1] + w11*c11[1];
|
||||
col[2] = w00*c00[2] + w10*c10[2] + w01*c01[2] + w11*c11[2];
|
||||
col[3] = w00*c00[3] + w10*c10[3] + w01*c01[3] + w11*c11[3];
|
||||
}
|
||||
}
|
||||
else col[0] = col[1] = col[2] = col[3] = 0.f;
|
||||
}
|
||||
|
||||
// as above, sampling only one channel
|
||||
void qd_getPixelLerpChan(CompBuf* src, float u, float v, int chan, float* out)
|
||||
{
|
||||
const float ufl = floorf(u), vfl = floorf(v);
|
||||
const int x1 = (int)ufl, y1 = (int)vfl;
|
||||
const int x2 = (int)ceilf(u), y2 = (int)ceilf(v);
|
||||
if (chan >= src->type) chan = 0;
|
||||
if ((x2 >= 0) && (y2 >= 0) && (x1 < src->x) && (y1 < src->y)) {
|
||||
const float B[4] = {0,0,0,0};
|
||||
const int ox1 = (x1 < 0), oy1 = (y1 < 0), ox2 = (x2 >= src->x), oy2 = (y2 >= src->y);
|
||||
const float* c00 = (ox1 || oy1) ? B : &src->rect[(x1 + y1*src->x)*src->type + chan];
|
||||
const float* c10 = (ox2 || oy1) ? B : &src->rect[(x2 + y1*src->x)*src->type + chan];
|
||||
const float* c01 = (ox1 || oy2) ? B : &src->rect[(x1 + y2*src->x)*src->type + chan];
|
||||
const float* c11 = (ox2 || oy2) ? B : &src->rect[(x2 + y2*src->x)*src->type + chan];
|
||||
const float uf = u - ufl, vf = v - vfl;
|
||||
const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf;
|
||||
out[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0];
|
||||
}
|
||||
else *out = 0.f;
|
||||
}
|
||||
|
||||
|
||||
CompBuf* qd_downScaledCopy(CompBuf* src, int scale)
|
||||
{
|
||||
CompBuf* fbuf;
|
||||
if (scale <= 1)
|
||||
fbuf = dupalloc_compbuf(src);
|
||||
else {
|
||||
int nw = src->x/scale, nh = src->y/scale;
|
||||
if ((2*(src->x % scale)) > scale) nw++;
|
||||
if ((2*(src->y % scale)) > scale) nh++;
|
||||
fbuf = alloc_compbuf(nw, nh, src->type, 1);
|
||||
{
|
||||
int x, y, xx, yy, sx, sy, mx, my;
|
||||
float colsum[4];
|
||||
float fscale = 1.f/(float)(scale*scale);
|
||||
for (y=0; y<nh; y++) {
|
||||
fRGB* fcolp = (fRGB*)&fbuf->rect[y*fbuf->x*fbuf->type];
|
||||
yy = y*scale;
|
||||
my = yy + scale;
|
||||
if (my > src->y) my = src->y;
|
||||
for (x=0; x<nw; x++) {
|
||||
xx = x*scale;
|
||||
mx = xx + scale;
|
||||
if (mx > src->x) mx = src->x;
|
||||
colsum[0] = colsum[1] = colsum[2] = 0.f;
|
||||
for (sy=yy; sy<my; sy++) {
|
||||
fRGB* scolp = (fRGB*)&src->rect[sy*src->x*src->type];
|
||||
for (sx=xx; sx<mx; sx++)
|
||||
fRGB_add(colsum, scolp[sx]);
|
||||
}
|
||||
fRGB_mult(colsum, fscale);
|
||||
fRGB_copy(fcolp[x], colsum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fbuf;
|
||||
}
|
||||
|
||||
// fast g.blur, per channel
|
||||
// xy var. bits 1 & 2 ca be used to blur in x or y direction separately
|
||||
void IIR_gauss(CompBuf* src, float sigma, int chan, int xy)
|
||||
{
|
||||
double q, q2, sc, cf[4], tsM[9], tsu[3], tsv[3];
|
||||
float *X, *Y, *W;
|
||||
int i, x, y, sz;
|
||||
|
||||
// <0.5 not valid, though can have a possibly useful sort of sharpening effect
|
||||
if (sigma < 0.5) return;
|
||||
|
||||
if ((xy < 1) || (xy > 3)) xy = 3;
|
||||
|
||||
// see "Recursive Gabor Filtering" by Young/VanVliet
|
||||
// all factors here in double.prec. Required, because for single.prec it seems to blow up if sigma > ~200
|
||||
if (sigma >= 3.556)
|
||||
q = 0.9804*(sigma - 3.556) + 2.5091;
|
||||
else // sigma >= 0.5
|
||||
q = (0.0561*sigma + 0.5784)*sigma - 0.2568;
|
||||
q2 = q*q;
|
||||
sc = (1.1668 + q)*(3.203729649 + (2.21566 + q)*q);
|
||||
// no gabor filtering here, so no complex multiplies, just the regular coefs.
|
||||
// all negated here, so as not to have to recalc Triggs/Sdika matrix
|
||||
cf[1] = q*(5.788961737 + (6.76492 + 3.0*q)*q)/ sc;
|
||||
cf[2] = -q2*(3.38246 + 3.0*q)/sc;
|
||||
// 0 & 3 unchanged
|
||||
cf[3] = q2*q/sc;
|
||||
cf[0] = 1.0 - cf[1] - cf[2] - cf[3];
|
||||
|
||||
// Triggs/Sdika border corrections,
|
||||
// it seems to work, not entirely sure if it is actually totally correct,
|
||||
// Besides J.M.Geusebroek's anigauss.c (see http://www.science.uva.nl/~mark),
|
||||
// found one other implementation by Cristoph Lampert,
|
||||
// but neither seem to be quite the same, result seems to be ok sofar anyway.
|
||||
// Extra scale factor here to not have to do it in filter,
|
||||
// though maybe this had something to with the precision errors
|
||||
sc = cf[0]/((1.0 + cf[1] - cf[2] + cf[3])*(1.0 - cf[1] - cf[2] - cf[3])*(1.0 + cf[2] + (cf[1] - cf[3])*cf[3]));
|
||||
tsM[0] = sc*(-cf[3]*cf[1] + 1.0 - cf[3]*cf[3] - cf[2]);
|
||||
tsM[1] = sc*((cf[3] + cf[1])*(cf[2] + cf[3]*cf[1]));
|
||||
tsM[2] = sc*(cf[3]*(cf[1] + cf[3]*cf[2]));
|
||||
tsM[3] = sc*(cf[1] + cf[3]*cf[2]);
|
||||
tsM[4] = sc*(-(cf[2] - 1.0)*(cf[2] + cf[3]*cf[1]));
|
||||
tsM[5] = sc*(-(cf[3]*cf[1] + cf[3]*cf[3] + cf[2] - 1.0)*cf[3]);
|
||||
tsM[6] = sc*(cf[3]*cf[1] + cf[2] + cf[1]*cf[1] - cf[2]*cf[2]);
|
||||
tsM[7] = sc*(cf[1]*cf[2] + cf[3]*cf[2]*cf[2] - cf[1]*cf[3]*cf[3] - cf[3]*cf[3]*cf[3] - cf[3]*cf[2] + cf[3]);
|
||||
tsM[8] = sc*(cf[3]*(cf[1] + cf[3]*cf[2]));
|
||||
|
||||
#define YVV(L)\
|
||||
{\
|
||||
W[0] = cf[0]*X[0] + cf[1]*X[0] + cf[2]*X[0] + cf[3]*X[0];\
|
||||
W[1] = cf[0]*X[1] + cf[1]*W[0] + cf[2]*X[0] + cf[3]*X[0];\
|
||||
W[2] = cf[0]*X[2] + cf[1]*W[1] + cf[2]*W[0] + cf[3]*X[0];\
|
||||
for (i=3; i<L; i++)\
|
||||
W[i] = cf[0]*X[i] + cf[1]*W[i-1] + cf[2]*W[i-2] + cf[3]*W[i-3];\
|
||||
tsu[0] = W[L-1] - X[L-1];\
|
||||
tsu[1] = W[L-2] - X[L-1];\
|
||||
tsu[2] = W[L-3] - X[L-1];\
|
||||
tsv[0] = tsM[0]*tsu[0] + tsM[1]*tsu[1] + tsM[2]*tsu[2] + X[L-1];\
|
||||
tsv[1] = tsM[3]*tsu[0] + tsM[4]*tsu[1] + tsM[5]*tsu[2] + X[L-1];\
|
||||
tsv[2] = tsM[6]*tsu[0] + tsM[7]*tsu[1] + tsM[8]*tsu[2] + X[L-1];\
|
||||
Y[L-1] = cf[0]*W[L-1] + cf[1]*tsv[0] + cf[2]*tsv[1] + cf[3]*tsv[2];\
|
||||
Y[L-2] = cf[0]*W[L-2] + cf[1]*Y[L-1] + cf[2]*tsv[0] + cf[3]*tsv[1];\
|
||||
Y[L-3] = cf[0]*W[L-3] + cf[1]*Y[L-2] + cf[2]*Y[L-1] + cf[3]*tsv[0];\
|
||||
for (i=L-4; i>=0; i--)\
|
||||
Y[i] = cf[0]*W[i] + cf[1]*Y[i+1] + cf[2]*Y[i+2] + cf[3]*Y[i+3];\
|
||||
}
|
||||
|
||||
// intermediate buffers
|
||||
sz = MAX2(src->x, src->y);
|
||||
X = MEM_callocN(sz*sizeof(float), "IIR_gauss X buf");
|
||||
Y = MEM_callocN(sz*sizeof(float), "IIR_gauss Y buf");
|
||||
W = MEM_callocN(sz*sizeof(float), "IIR_gauss W buf");
|
||||
if (xy & 1) { // H
|
||||
for (y=0; y<src->y; ++y) {
|
||||
const int yx = y*src->x;
|
||||
for (x=0; x<src->x; ++x)
|
||||
X[x] = src->rect[(x + yx)*src->type + chan];
|
||||
YVV(src->x);
|
||||
for (x=0; x<src->x; ++x)
|
||||
src->rect[(x + yx)*src->type + chan] = Y[x];
|
||||
}
|
||||
}
|
||||
if (xy & 2) { // V
|
||||
for (x=0; x<src->x; ++x) {
|
||||
for (y=0; y<src->y; ++y)
|
||||
X[y] = src->rect[(x + y*src->x)*src->type + chan];
|
||||
YVV(src->y);
|
||||
for (y=0; y<src->y; ++y)
|
||||
src->rect[(x + y*src->x)*src->type + chan] = Y[y];
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(X);
|
||||
MEM_freeN(W);
|
||||
MEM_freeN(Y);
|
||||
#undef YVV
|
||||
}
|
||||
|
||||
|
||||
@@ -176,7 +176,46 @@ void do_hsva_to_rgba(bNode *node, float *out, float *in);
|
||||
void do_ycca_to_rgba(bNode *node, float *out, float *in);
|
||||
|
||||
void gamma_correct_compbuf(CompBuf *img, int inversed);
|
||||
void convolve(CompBuf* dst, CompBuf* in1, CompBuf* in2);
|
||||
|
||||
extern void node_ID_title_cb(void *node_v, void *unused_v);
|
||||
|
||||
|
||||
/* utility functions used by glare, tonemap and lense distortion */
|
||||
/* soms macros for color handling */
|
||||
typedef float fRGB[4];
|
||||
/* clear color */
|
||||
#define fRGB_clear(c) { c[0]=c[1]=c[2]=0.f; }
|
||||
/* copy c2 to c1 */
|
||||
#define fRGB_copy(c1, c2) { c1[0]=c2[0]; c1[1]=c2[1]; c1[2]=c2[2]; }
|
||||
/* add c2 to c1 */
|
||||
#define fRGB_add(c1, c2) { c1[0]+=c2[0]; c1[1]+=c2[1]; c1[2]+=c2[2]; }
|
||||
/* subtract c2 from c1 */
|
||||
#define fRGB_sub(c1, c2) { c1[0]-=c2[0]; c1[1]-=c2[1]; c1[2]-=c2[2]; }
|
||||
/* multiply c by float value s */
|
||||
#define fRGB_mult(c, s) { c[0]*=s; c[1]*=s; c[2]*=s; }
|
||||
/* multiply c2 by s and add to c1 */
|
||||
#define fRGB_madd(c1, c2, s) { c1[0]+=c2[0]*s; c1[1]+=c2[1]*s; c1[2]+=c2[2]*s; }
|
||||
/* multiply c2 by color c1 */
|
||||
#define fRGB_colormult(c, cs) { c[0]*=cs[0]; c[1]*=cs[1]; c[2]*=cs[2]; }
|
||||
/* multiply c2 by color c3 and add to c1 */
|
||||
#define fRGB_colormadd(c1, c2, c3) { c1[0]+=c2[0]*c3[0]; c1[1]+=c2[1]*c3[1]; c1[2]+=c2[2]*c3[2]; }
|
||||
/* multiply c2 by color rgb, rgb as separate arguments */
|
||||
#define fRGB_rgbmult(c, r, g, b) { c[0]*=(r); c[1]*=(g); c[2]*=(b); }
|
||||
/* swap colors c1 & c2 */
|
||||
#define fRGB_swap(c1, c2) { float _t=c1[0]; c1[0]=c2[0]; c2[0]=_t;\
|
||||
_t=c1[1]; c1[1]=c2[1]; c2[1]=_t;\
|
||||
_t=c1[2]; c1[2]=c2[2]; c2[2]=_t; }
|
||||
|
||||
void qd_getPixel(CompBuf* src, int x, int y, float* col);
|
||||
void qd_setPixel(CompBuf* src, int x, int y, float* col);
|
||||
void qd_addPixel(CompBuf* src, int x, int y, float* col);
|
||||
void qd_multPixel(CompBuf* src, int x, int y, float f);
|
||||
void qd_getPixelLerpWrap(CompBuf* src, float u, float v, float* col);
|
||||
void qd_getPixelLerp(CompBuf* src, float u, float v, float* col);
|
||||
void qd_getPixelLerpChan(CompBuf* src, float u, float v, int chan, float* out);
|
||||
CompBuf* qd_downScaledCopy(CompBuf* src, int scale);
|
||||
void IIR_gauss(CompBuf* src, float sigma, int chan, int xy);
|
||||
/* end utility funcs */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1057,18 +1057,22 @@ static int node_composit_buts_blur(uiBlock *block, bNodeTree *ntree, bNode *node
|
||||
char str[256];
|
||||
|
||||
uiBlockBeginAlign(block);
|
||||
sprintf(str, "Filter Type%%t|Flat %%x%d|Tent %%x%d|Quad %%x%d|Cubic %%x%d|Gauss %%x%d|CatRom %%x%d|Mitch %%x%d", R_FILTER_BOX, R_FILTER_TENT, R_FILTER_QUAD, R_FILTER_CUBIC, R_FILTER_GAUSS, R_FILTER_CATROM, R_FILTER_MITCH);
|
||||
uiDefButS(block, MENU, B_NODE_EXEC+node->nr,str,
|
||||
sprintf(str, "Filter Type%%t|Flat %%x%d|Tent %%x%d|Quad %%x%d|Cubic %%x%d|Gauss %%x%d|Fast Gauss%%x%d|CatRom %%x%d|Mitch %%x%d", R_FILTER_BOX, R_FILTER_TENT, R_FILTER_QUAD, R_FILTER_CUBIC, R_FILTER_GAUSS, R_FILTER_FAST_GAUSS, R_FILTER_CATROM, R_FILTER_MITCH);
|
||||
uiDefButS(block, MENU, B_NODE_EXEC+node->nr,str,
|
||||
butr->xmin, dy, dx*2, 19,
|
||||
&nbd->filtertype, 0, 0, 0, 0, "Set sampling filter for blur");
|
||||
dy-=19;
|
||||
uiDefButC(block, TOG, B_NODE_EXEC+node->nr, "Bokeh",
|
||||
butr->xmin, dy, dx, 19,
|
||||
&nbd->bokeh, 0, 0, 0, 0, "Uses circular filter, warning it's slow!");
|
||||
uiDefButC(block, TOG, B_NODE_EXEC+node->nr, "Gamma",
|
||||
butr->xmin+dx, dy, dx, 19,
|
||||
&nbd->gamma, 0, 0, 0, 0, "Applies filter on gamma corrected values");
|
||||
|
||||
dy-=19;
|
||||
if (nbd->filtertype != R_FILTER_FAST_GAUSS) {
|
||||
uiDefButC(block, TOG, B_NODE_EXEC+node->nr, "Bokeh",
|
||||
butr->xmin, dy, dx, 19,
|
||||
&nbd->bokeh, 0, 0, 0, 0, "Uses circular filter, warning it's slow!");
|
||||
uiDefButC(block, TOG, B_NODE_EXEC+node->nr, "Gamma",
|
||||
butr->xmin+dx, dy, dx, 19,
|
||||
&nbd->gamma, 0, 0, 0, 0, "Applies filter on gamma corrected values");
|
||||
} else {
|
||||
uiBlockEndAlign(block);
|
||||
uiBlockBeginAlign(block);
|
||||
}
|
||||
dy-=19;
|
||||
bt=uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "X:",
|
||||
butr->xmin, dy, dx, 19,
|
||||
@@ -1076,6 +1080,7 @@ static int node_composit_buts_blur(uiBlock *block, bNodeTree *ntree, bNode *node
|
||||
bt=uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Y:",
|
||||
butr->xmin+dx, dy, dx, 19,
|
||||
&nbd->sizey, 0, 256, 0, 0, "");
|
||||
uiBlockEndAlign(block);
|
||||
}
|
||||
return 57;
|
||||
}
|
||||
@@ -1134,6 +1139,145 @@ static int node_composit_buts_defocus(uiBlock *block, bNodeTree *ntree, bNode *n
|
||||
return 228;
|
||||
}
|
||||
|
||||
|
||||
/* qdn: glare node */
|
||||
static int node_composit_buts_glare(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
|
||||
{
|
||||
if(block) {
|
||||
NodeGlare *ndg = node->storage;
|
||||
short dy = butr->ymin + 152, dx = butr->xmax - butr->xmin;
|
||||
char* mn1 = "Type%t|Ghosts%x3|Streaks%x2|Fog Glow%x1|Simple Star%x0";
|
||||
char* mn2 = "Quality/Speed%t|High/Slow%x0|Medium/Medium%x1|Low/Fast%x2";
|
||||
uiDefButC(block, MENU, B_NODE_EXEC+node->nr, mn1,
|
||||
butr->xmin, dy, dx, 19,
|
||||
&ndg->type, 0, 0, 0, 0, "Glow/Flare/Bloom type");
|
||||
uiDefButC(block, MENU, B_NODE_EXEC+node->nr, mn2,
|
||||
butr->xmin, dy-19, dx, 19,
|
||||
&ndg->quality, 0, 0, 0, 0,
|
||||
"Quality speed trade off, if not set to high quality, effect will be applied to low-res copy of source image");
|
||||
if (ndg->type != 1) {
|
||||
uiDefButC(block, NUM, B_NODE_EXEC+node->nr, "Iterations:",
|
||||
butr->xmin, dy-38, dx, 19,
|
||||
&ndg->iter, 2, 5, 1, 0,
|
||||
"higher values will generate longer/more streaks/ghosts");
|
||||
if (ndg->type != 0)
|
||||
uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "ColMod:",
|
||||
butr->xmin, dy-57, dx, 19,
|
||||
&ndg->colmod, 0, 1, 10, 0,
|
||||
"Amount of Color Modulation, modulates colors of streaks and ghosts for a spectral dispersion effect");
|
||||
}
|
||||
uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Mix:",
|
||||
butr->xmin, dy-76, dx, 19,
|
||||
&ndg->mix, -1, 1, 10, 0,
|
||||
"Mix balance, -1 is original image only, 0 is exact 50/50 mix, 1 is processed image only");
|
||||
uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Threshold:",
|
||||
butr->xmin, dy-95, dx, 19,
|
||||
&ndg->threshold, 0, 1000, 10, 0,
|
||||
"Brightness threshold, the glarefilter will be applied only to pixels brighter than this value");
|
||||
if ((ndg->type == 2) || (ndg->type == 0))
|
||||
{
|
||||
if (ndg->type == 2) {
|
||||
uiDefButC(block, NUM, B_NODE_EXEC+node->nr, "streaks:",
|
||||
butr->xmin, dy-114, dx, 19,
|
||||
&ndg->angle, 2, 16, 1000, 0,
|
||||
"Total number of streaks");
|
||||
uiDefButC(block, NUM, B_NODE_EXEC+node->nr, "AngOfs:",
|
||||
butr->xmin, dy-133, dx, 19,
|
||||
&ndg->angle_ofs, 0, 180, 1000, 0,
|
||||
"Streak angle rotation offset in degrees");
|
||||
}
|
||||
uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Fade:",
|
||||
butr->xmin, dy-152, dx, 19,
|
||||
&ndg->fade, 0.75, 1, 5, 0,
|
||||
"Streak fade out factor");
|
||||
}
|
||||
if (ndg->type == 0)
|
||||
uiDefButC(block, TOG, B_NODE_EXEC+node->nr, "Rot45",
|
||||
butr->xmin, dy-114, dx, 19,
|
||||
&ndg->angle, 0, 0, 0, 0,
|
||||
"simple star filter, add 45 degree rotation offset");
|
||||
if ((ndg->type == 1) || (ndg->type > 3)) // PBGH and fog glow
|
||||
uiDefButC(block, NUM, B_NODE_EXEC+node->nr, "Size:",
|
||||
butr->xmin, dy-114, dx, 19,
|
||||
&ndg->size, 6, 9, 1000, 0,
|
||||
"glow/glare size (not actual size, relative to initial size of bright area of pixels)");
|
||||
}
|
||||
return 171;
|
||||
}
|
||||
|
||||
/* qdn: tonemap node */
|
||||
static int node_composit_buts_tonemap(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
|
||||
{
|
||||
if(block) {
|
||||
NodeTonemap *ntm = node->storage;
|
||||
short dy = butr->ymin + 76, dx = butr->xmax - butr->xmin;
|
||||
char* mn = "Type%t|R/D Photoreceptor%x1|Rh Simple%x0";
|
||||
|
||||
uiBlockBeginAlign(block);
|
||||
uiDefButI(block, MENU, B_NODE_EXEC+node->nr, mn,
|
||||
butr->xmin, dy, dx, 19,
|
||||
&ntm->type, 0, 0, 0, 0,
|
||||
"Tone mapping type");
|
||||
if (ntm->type == 0) {
|
||||
uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Key:",
|
||||
butr->xmin, dy-19, dx, 19,
|
||||
&ntm->key, 0, 1, 5, 0,
|
||||
"The value the average luminance is mapped to");
|
||||
uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Offset:",
|
||||
butr->xmin, dy-38, dx, 19,
|
||||
&ntm->offset, 0.001, 10, 5, 0,
|
||||
"Tonemap offset, normally always 1, but can be used as an extra control to alter the brightness curve");
|
||||
uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Gamma:",
|
||||
butr->xmin, dy-57, dx, 19,
|
||||
&ntm->gamma, 0.001, 3, 5, 0,
|
||||
"Gamma factor, if not used, set to 1");
|
||||
}
|
||||
else {
|
||||
uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Intensity:",
|
||||
butr->xmin, dy-19, dx, 19,
|
||||
&ntm->f, -8, 8, 10, 0, "if less than zero, darkens image, otherwise makes it brighter");
|
||||
uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Contrast:",
|
||||
butr->xmin, dy-38, dx, 19,
|
||||
&ntm->m, 0, 1, 5, 0, "Set to 0 to use estimate from input image");
|
||||
uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Adaptation:",
|
||||
butr->xmin, dy-57, dx, 19,
|
||||
&ntm->a, 0, 1, 5, 0, "if 0, global, if 1, based on pixel intensity");
|
||||
uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "ColCorrect:",
|
||||
butr->xmin, dy-76, dx, 19,
|
||||
&ntm->c, 0, 1, 5, 0, "color correction, if 0, same for all channels, if 1, each independent");
|
||||
}
|
||||
uiBlockEndAlign(block);
|
||||
}
|
||||
return 95;
|
||||
}
|
||||
|
||||
/* qdn: lens distortion node */
|
||||
static int node_composit_buts_lensdist(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
|
||||
{
|
||||
if(block) {
|
||||
NodeLensDist *nld = node->storage;
|
||||
short dy = butr->ymin + 19, dx = butr->xmax - butr->xmin;
|
||||
uiBlockBeginAlign(block);
|
||||
uiDefButS(block, TOG, B_NODE_EXEC+node->nr, "Projector",
|
||||
butr->xmin, dy, dx, 19,
|
||||
&nld->proj, 0, 0, 0, 0,
|
||||
"Enable/disable projector mode, effect is applied in horizontal direction only");
|
||||
if (!nld->proj) {
|
||||
uiDefButS(block, TOG, B_NODE_EXEC+node->nr, "Jitter",
|
||||
butr->xmin, dy-19, dx/2, 19,
|
||||
&nld->jit, 0, 0, 0, 0,
|
||||
"Enable/disable jittering, faster, but also noisier");
|
||||
uiDefButS(block, TOG, B_NODE_EXEC+node->nr, "Fit",
|
||||
butr->xmin+dx/2, dy-19, dx/2, 19,
|
||||
&nld->fit, 0, 0, 0, 0,
|
||||
"For positive distortion factor only, scale image such that black areas are not visible");
|
||||
}
|
||||
uiBlockEndAlign(block);
|
||||
}
|
||||
return 38;
|
||||
}
|
||||
|
||||
|
||||
static int node_composit_buts_vecblur(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
|
||||
{
|
||||
if(block) {
|
||||
@@ -1617,10 +1761,22 @@ static void node_composit_set_butfunc(bNodeType *ntype)
|
||||
case CMP_NODE_BLUR:
|
||||
ntype->butfunc= node_composit_buts_blur;
|
||||
break;
|
||||
/* qdn: defocus node */
|
||||
/* qdn: defocus node */
|
||||
case CMP_NODE_DEFOCUS:
|
||||
ntype->butfunc = node_composit_buts_defocus;
|
||||
break;
|
||||
/* qdn: glare node */
|
||||
case CMP_NODE_GLARE:
|
||||
ntype->butfunc = node_composit_buts_glare;
|
||||
break;
|
||||
/* qdn: tonemap node */
|
||||
case CMP_NODE_TONEMAP:
|
||||
ntype->butfunc = node_composit_buts_tonemap;
|
||||
break;
|
||||
/* qdn: lens distortion node */
|
||||
case CMP_NODE_LENSDIST:
|
||||
ntype->butfunc = node_composit_buts_lensdist;
|
||||
break;
|
||||
case CMP_NODE_VECBLUR:
|
||||
ntype->butfunc= node_composit_buts_vecblur;
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user