Blender V2.61 - r43446

node_composite_lensdist.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2006 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): Alfredo de Greef  (eeshlo)
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include "node_composite_util.h"
00034 
00035 static bNodeSocketTemplate cmp_node_lensdist_in[]= {
00036     {   SOCK_RGBA, 1, "Image",          1.0f, 1.0f, 1.0f, 1.0f},
00037     {   SOCK_FLOAT, 1, "Distort",   0.f, 0.f, 0.f, 0.f, -0.999f, 1.f, PROP_NONE},
00038     {   SOCK_FLOAT, 1, "Dispersion", 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, PROP_NONE},
00039     {   -1, 0, ""   }
00040 };
00041 static bNodeSocketTemplate cmp_node_lensdist_out[]= {
00042     {   SOCK_RGBA, 0, "Image"},
00043     {   -1, 0, ""   }
00044 };
00045 
00046 /* assumes *dst is type RGBA */
00047 static void lensDistort(CompBuf *dst, CompBuf *src, float kr, float kg, float kb, int jit, int proj, int fit)
00048 {
00049     int x, y, z;
00050     const float cx = 0.5f*(float)dst->x, cy = 0.5f*(float)dst->y;
00051 
00052     if (proj) {
00053         // shift
00054         CompBuf *tsrc = dupalloc_compbuf(src);
00055         
00056         for (z=0; z<tsrc->type; ++z)
00057             IIR_gauss(tsrc, (kr+0.5f)*(kr+0.5f), z, 1);
00058         kr *= 20.f;
00059         
00060         for (y=0; y<dst->y; y++) {
00061             fRGB *colp = (fRGB*)&dst->rect[y*dst->x*dst->type];
00062             const float v = (y + 0.5f)/(float)dst->y;
00063             
00064             for (x=0; x<dst->x; x++) {
00065                 const float u = (x + 0.5f)/(float)dst->x;
00066                 
00067                 qd_getPixelLerpChan(tsrc, (u*dst->x + kr) - 0.5f, v*dst->y - 0.5f, 0, colp[x]);
00068                 if (tsrc->type == CB_VAL)
00069                     colp[x][1] = tsrc->rect[x + y*tsrc->x];
00070                 else
00071                     colp[x][1] = tsrc->rect[(x + y*tsrc->x)*tsrc->type + 1];
00072                 qd_getPixelLerpChan(tsrc, (u*dst->x - kr) - 0.5f, v*dst->y - 0.5f, 2, colp[x]+2);
00073                 
00074                 /* set alpha */
00075                 colp[x][3]= 1.0f;
00076             }
00077         }
00078         free_compbuf(tsrc);
00079     }
00080     else {
00081         // Spherical
00082         // Scale factor to make bottom/top & right/left sides fit in window after deform
00083         // so in the case of pincushion (kn < 0), corners will be outside window.
00084         // Now also optionally scales image such that black areas are not visible when distort factor is positive
00085         // (makes distorted corners match window corners, but really only valid if mk<=0.5)
00086         const float mk = MAX3(kr, kg, kb);
00087         const float sc = (fit && (mk > 0.f)) ? (1.f/(1.f + 2.f*mk)) : (1.f/(1.f + mk));
00088         const float drg = 4.f*(kg - kr), dgb = 4.f*(kb - kg);
00089         
00090         kr *= 4.f, kg *= 4.f, kb *= 4.f;
00091 
00092         for (y=0; y<dst->y; y++) {
00093             fRGB *colp = (fRGB*)&dst->rect[y*dst->x*dst->type];
00094             const float v = sc*((y + 0.5f) - cy)/cy;
00095             
00096             for (x=0; x<dst->x; x++) {
00097                 int dr = 0, dg = 0, db = 0;
00098                 float d, t, ln[6] = {0, 0, 0, 0, 0, 0};
00099                 fRGB c1, tc = {0, 0, 0, 0};
00100                 const float u = sc*((x + 0.5f) - cx)/cx;
00101                 int sta = 0, mid = 0, end = 0;
00102                 
00103                 if ((t = 1.f - kr*(u*u + v*v)) >= 0.f) {
00104                     d = 1.f/(1.f + sqrtf(t));
00105                     ln[0] = (u*d + 0.5f)*dst->x - 0.5f, ln[1] = (v*d + 0.5f)*dst->y - 0.5f;
00106                     sta = 1;
00107                 }
00108                 if ((t = 1.f - kg*(u*u + v*v)) >= 0.f) {
00109                     d = 1.f/(1.f + sqrtf(t));
00110                     ln[2] = (u*d + 0.5f)*dst->x - 0.5f, ln[3] = (v*d + 0.5f)*dst->y - 0.5f;
00111                     mid = 1;
00112                 }
00113                 if ((t = 1.f - kb*(u*u + v*v)) >= 0.f) {
00114                     d = 1.f/(1.f + sqrtf(t));
00115                     ln[4] = (u*d + 0.5f)*dst->x - 0.5f, ln[5] = (v*d + 0.5f)*dst->y - 0.5f;
00116                     end = 1;
00117                 }
00118     
00119                 if (sta && mid && end) {
00120                     // RG
00121                     const int dx = ln[2] - ln[0], dy = ln[3] - ln[1];
00122                     const float dsf = sqrtf(dx*dx + dy*dy) + 1.f;
00123                     const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf);
00124                     const float sd = 1.f/(float)ds;
00125                     
00126                     for (z=0; z<ds; ++z) {
00127                         const float tz = ((float)z + (jit ? BLI_frand() : 0.5f))*sd;
00128                         t = 1.f - (kr + tz*drg)*(u*u + v*v);
00129                         d = 1.f / (1.f + sqrtf(t));
00130                         qd_getPixelLerp(src, (u*d + 0.5f)*dst->x - 0.5f, (v*d + 0.5f)*dst->y - 0.5f, c1);
00131                         if (src->type == CB_VAL) c1[1] = c1[2] = c1[0];
00132                         tc[0] += (1.f-tz)*c1[0], tc[1] += tz*c1[1];
00133                         dr++, dg++;
00134                     }
00135                     // GB
00136                     {
00137                         const int dx = ln[4] - ln[2], dy = ln[5] - ln[3];
00138                         const float dsf = sqrtf(dx*dx + dy*dy) + 1.f;
00139                         const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf);
00140                         const float sd = 1.f/(float)ds;
00141                         
00142                         for (z=0; z<ds; ++z) {
00143                             const float tz = ((float)z + (jit ? BLI_frand() : 0.5f))*sd;
00144                             t = 1.f - (kg + tz*dgb)*(u*u + v*v);
00145                             d = 1.f / (1.f + sqrtf(t));
00146                             qd_getPixelLerp(src, (u*d + 0.5f)*dst->x - 0.5f, (v*d + 0.5f)*dst->y - 0.5f, c1);
00147                             if (src->type == CB_VAL) c1[1] = c1[2] = c1[0];
00148                             tc[1] += (1.f-tz)*c1[1], tc[2] += tz*c1[2];
00149                             dg++, db++;
00150                         }
00151                     }
00152                 }
00153     
00154                 if (dr) colp[x][0] = 2.f*tc[0] / (float)dr;
00155                 if (dg) colp[x][1] = 2.f*tc[1] / (float)dg;
00156                 if (db) colp[x][2] = 2.f*tc[2] / (float)db;
00157     
00158                 /* set alpha */
00159                 colp[x][3]= 1.0f;
00160             }
00161         }
00162     }
00163 }
00164 
00165 
00166 static void node_composit_exec_lensdist(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
00167 {
00168     CompBuf *new, *img = in[0]->data;
00169     NodeLensDist *nld = node->storage;
00170     const float k = MAX2(MIN2(in[1]->vec[0], 1.f), -0.999f);
00171     // smaller dispersion range for somewhat more control
00172     const float d = 0.25f*MAX2(MIN2(in[2]->vec[0], 1.f), 0.f);
00173     const float kr = MAX2(MIN2((k+d), 1.f), -0.999f), kb = MAX2(MIN2((k-d), 1.f), -0.999f);
00174 
00175     if ((img==NULL) || (out[0]->hasoutput==0)) return;
00176 
00177     new = alloc_compbuf(img->x, img->y, CB_RGBA, 1);
00178 
00179     lensDistort(new, img, (nld->proj ? d : kr), k, kb, nld->jit, nld->proj, nld->fit);
00180 
00181     out[0]->data = new;
00182 }
00183 
00184 
00185 static void node_composit_init_lensdist(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
00186 {
00187     NodeLensDist *nld = MEM_callocN(sizeof(NodeLensDist), "node lensdist data");
00188     nld->jit = nld->proj = nld->fit = 0;
00189     node->storage = nld;
00190 }
00191 
00192 
00193 void register_node_type_cmp_lensdist(bNodeTreeType *ttype)
00194 {
00195     static bNodeType ntype;
00196 
00197     node_type_base(ttype, &ntype, CMP_NODE_LENSDIST, "Lens Distortion", NODE_CLASS_DISTORT, NODE_OPTIONS);
00198     node_type_socket_templates(&ntype, cmp_node_lensdist_in, cmp_node_lensdist_out);
00199     node_type_size(&ntype, 150, 120, 200);
00200     node_type_init(&ntype, node_composit_init_lensdist);
00201     node_type_storage(&ntype, "NodeLensDist", node_free_standard_storage, node_copy_standard_storage);
00202     node_type_exec(&ntype, node_composit_exec_lensdist);
00203 
00204     nodeRegisterType(ttype, &ntype);
00205 }