Blender  V2.59
CMP_util.c
Go to the documentation of this file.
00001 /*
00002  * $Id: CMP_util.c 38344 2011-07-12 18:59:54Z jbakker $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2006 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): none yet.
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00035 #include "CMP_util.h"
00036 
00037 CompBuf *alloc_compbuf(int sizex, int sizey, int type, int alloc)
00038 {
00039         CompBuf *cbuf= MEM_callocN(sizeof(CompBuf), "compbuf");
00040         
00041         cbuf->x= sizex;
00042         cbuf->y= sizey;
00043         cbuf->xrad= sizex/2;
00044         cbuf->yrad= sizey/2;
00045         
00046         cbuf->type= type;
00047         if(alloc) {
00048                 if(cbuf->type==CB_RGBA)
00049                         cbuf->rect= MEM_mapallocN(4*sizeof(float)*sizex*sizey, "compbuf RGBA rect");
00050                 else if(cbuf->type==CB_VEC3)
00051                         cbuf->rect= MEM_mapallocN(3*sizeof(float)*sizex*sizey, "compbuf Vector3 rect");
00052                 else if(cbuf->type==CB_VEC2)
00053                         cbuf->rect= MEM_mapallocN(2*sizeof(float)*sizex*sizey, "compbuf Vector2 rect");
00054                 else
00055                         cbuf->rect= MEM_mapallocN(sizeof(float)*sizex*sizey, "compbuf Fac rect");
00056                 cbuf->malloc= 1;
00057         }
00058         cbuf->disprect.xmin= 0;
00059         cbuf->disprect.ymin= 0;
00060         cbuf->disprect.xmax= sizex;
00061         cbuf->disprect.ymax= sizey;
00062         
00063         return cbuf;
00064 }
00065 
00066 CompBuf *dupalloc_compbuf(CompBuf *cbuf)
00067 {
00068         CompBuf *dupbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1);
00069         if(dupbuf) {
00070                 memmove(dupbuf->rect, cbuf->rect, cbuf->type*sizeof(float)*cbuf->x*cbuf->y);
00071         
00072                 dupbuf->xof= cbuf->xof;
00073                 dupbuf->yof= cbuf->yof;
00074         }       
00075         return dupbuf;
00076 }
00077 
00078 /* instead of reference counting, we create a list */
00079 CompBuf *pass_on_compbuf(CompBuf *cbuf)
00080 {
00081         CompBuf *dupbuf= (cbuf)? alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 0): NULL;
00082         CompBuf *lastbuf;
00083         
00084         if(dupbuf) {
00085                 dupbuf->rect= cbuf->rect;
00086                 dupbuf->xof= cbuf->xof;
00087                 dupbuf->yof= cbuf->yof;
00088                 dupbuf->malloc= 0;
00089                 
00090                 /* get last buffer in list, and append dupbuf */
00091                 for(lastbuf= cbuf; lastbuf; lastbuf= lastbuf->next)
00092                         if(lastbuf->next==NULL)
00093                                 break;
00094                 lastbuf->next= dupbuf;
00095                 dupbuf->prev= lastbuf;
00096         }       
00097         return dupbuf;
00098 }
00099 
00100 
00101 void free_compbuf(CompBuf *cbuf)
00102 {
00103         /* check referencing, then remove from list and set malloc tag */
00104         if(cbuf->prev || cbuf->next) {
00105                 if(cbuf->prev)
00106                         cbuf->prev->next= cbuf->next;
00107                 if(cbuf->next)
00108                         cbuf->next->prev= cbuf->prev;
00109                 if(cbuf->malloc) {
00110                         if(cbuf->prev)
00111                                 cbuf->prev->malloc= 1;
00112                         else
00113                                 cbuf->next->malloc= 1;
00114                         cbuf->malloc= 0;
00115                 }
00116         }
00117         
00118         if(cbuf->malloc && cbuf->rect)
00119                 MEM_freeN(cbuf->rect);
00120 
00121         MEM_freeN(cbuf);
00122 }
00123 
00124 void print_compbuf(char *str, CompBuf *cbuf)
00125 {
00126         printf("Compbuf %s %d %d %p\n", str, cbuf->x, cbuf->y, (void *)cbuf->rect);
00127         
00128 }
00129 
00130 void compbuf_set_node(CompBuf *cbuf, bNode *node)
00131 {
00132         if (cbuf) cbuf->node = node;
00133 }
00134 
00135 /* used for disabling node  (similar code in node_draw.c for disable line and node_edit for untangling nodes) */
00136 void node_compo_pass_on(bNode *node, bNodeStack **nsin, bNodeStack **nsout)
00137 {
00138         CompBuf *valbuf= NULL, *colbuf= NULL, *vecbuf= NULL;
00139         bNodeSocket *sock;
00140         int a;
00141         
00142         /* connect the first value buffer in with first value out */
00143         /* connect the first RGBA buffer in with first RGBA out */
00144         
00145         /* test the inputs */
00146         for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
00147                 if(nsin[a]->data) {
00148                         CompBuf *cbuf= nsin[a]->data;
00149                         if(cbuf->type==1 && valbuf==NULL) valbuf= cbuf;
00150                         if(cbuf->type==3 && vecbuf==NULL) vecbuf= cbuf;
00151                         if(cbuf->type==4 && colbuf==NULL) colbuf= cbuf;
00152                 }
00153         }
00154         
00155         /* outputs */
00156         if(valbuf || colbuf || vecbuf) {
00157                 for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
00158                         if(nsout[a]->hasoutput) {
00159                                 if(sock->type==SOCK_VALUE && valbuf) {
00160                                         nsout[a]->data= pass_on_compbuf(valbuf);
00161                                         valbuf= NULL;
00162                                 }
00163                                 if(sock->type==SOCK_VECTOR && vecbuf) {
00164                                         nsout[a]->data= pass_on_compbuf(vecbuf);
00165                                         vecbuf= NULL;
00166                                 }
00167                                 if(sock->type==SOCK_RGBA && colbuf) {
00168                                         nsout[a]->data= pass_on_compbuf(colbuf);
00169                                         colbuf= NULL;
00170                                 }
00171                         }
00172                 }
00173         }
00174 }
00175 
00176 
00177 CompBuf *get_cropped_compbuf(rcti *drect, float *rectf, int rectx, int recty, int type)
00178 {
00179         CompBuf *cbuf;
00180         rcti disprect= *drect;
00181         float *outfp;
00182         int dx, y;
00183         
00184         if(disprect.xmax>rectx) disprect.xmax= rectx;
00185         if(disprect.ymax>recty) disprect.ymax= recty;
00186         if(disprect.xmin>= disprect.xmax) return NULL;
00187         if(disprect.ymin>= disprect.ymax) return NULL;
00188         
00189         cbuf= alloc_compbuf(disprect.xmax-disprect.xmin, disprect.ymax-disprect.ymin, type, 1);
00190         outfp= cbuf->rect;
00191         rectf += type*(disprect.ymin*rectx + disprect.xmin);
00192         dx= type*cbuf->x;
00193         for(y=cbuf->y; y>0; y--, outfp+=dx, rectf+=type*rectx)
00194                 memcpy(outfp, rectf, sizeof(float)*dx);
00195         
00196         return cbuf;
00197 }
00198 
00199 CompBuf *scalefast_compbuf(CompBuf *inbuf, int newx, int newy)
00200 {
00201         CompBuf *outbuf; 
00202         float *rectf, *newrectf, *rf;
00203         int x, y, c, pixsize= inbuf->type;
00204         int ofsx, ofsy, stepx, stepy;
00205         
00206         if(inbuf->x==newx && inbuf->y==newy)
00207                 return dupalloc_compbuf(inbuf);
00208         
00209         outbuf= alloc_compbuf(newx, newy, inbuf->type, 1);
00210         newrectf= outbuf->rect;
00211         
00212         stepx = (65536.0 * (inbuf->x - 1.0) / (newx - 1.0)) + 0.5;
00213         stepy = (65536.0 * (inbuf->y - 1.0) / (newy - 1.0)) + 0.5;
00214         ofsy = 32768;
00215         
00216         for (y = newy; y > 0 ; y--){
00217                 rectf = inbuf->rect;
00218                 rectf += pixsize * (ofsy >> 16) * inbuf->x;
00219 
00220                 ofsy += stepy;
00221                 ofsx = 32768;
00222                 
00223                 for (x = newx ; x>0 ; x--) {
00224                         
00225                         rf= rectf + pixsize*(ofsx >> 16);
00226                         for(c=0; c<pixsize; c++)
00227                                 newrectf[c] = rf[c];
00228                         
00229                         newrectf+= pixsize;
00230                         
00231                         ofsx += stepx;
00232                 }
00233         }
00234         
00235         return outbuf;
00236 }
00237 
00238 void typecheck_compbuf_color(float *out, float *in, int outtype, int intype)
00239 {
00240         if(intype == outtype) {
00241                 memcpy(out, in, sizeof(float)*outtype);
00242         }
00243         else if(outtype==CB_VAL) {
00244                 if(intype==CB_VEC2) {
00245                         *out= 0.5f*(in[0]+in[1]);
00246                 }
00247                 else if(intype==CB_VEC3) {
00248                         *out= 0.333333f*(in[0]+in[1]+in[2]);
00249                 }
00250                 else if(intype==CB_RGBA) {
00251                         *out= in[0]*0.35f + in[1]*0.45f + in[2]*0.2f;
00252                 }
00253         }
00254         else if(outtype==CB_VEC2) {
00255                 if(intype==CB_VAL) {
00256                         out[0]= in[0];
00257                         out[1]= in[0];
00258                 }
00259                 else if(intype==CB_VEC3) {
00260                         out[0]= in[0];
00261                         out[1]= in[1];
00262                 }
00263                 else if(intype==CB_RGBA) {
00264                         out[0]= in[0];
00265                         out[1]= in[1];
00266                 }
00267         }
00268         else if(outtype==CB_VEC3) {
00269                 if(intype==CB_VAL) {
00270                         out[0]= in[0];
00271                         out[1]= in[0];
00272                         out[2]= in[0];
00273                 }
00274                 else if(intype==CB_VEC2) {
00275                         out[0]= in[0];
00276                         out[1]= in[1];
00277                         out[2]= 0.0f;
00278                 }
00279                 else if(intype==CB_RGBA) {
00280                         out[0]= in[0];
00281                         out[1]= in[1];
00282                         out[2]= in[2];
00283                 }
00284         }
00285         else if(outtype==CB_RGBA) {
00286                 if(intype==CB_VAL) {
00287                         out[0]= in[0];
00288                         out[1]= in[0];
00289                         out[2]= in[0];
00290                         out[3]= 1.0f;
00291                 }
00292                 else if(intype==CB_VEC2) {
00293                         out[0]= in[0];
00294                         out[1]= in[1];
00295                         out[2]= 0.0f;
00296                         out[3]= 1.0f;
00297                 }
00298                 else if(intype==CB_VEC3) {
00299                         out[0]= in[0];
00300                         out[1]= in[1];
00301                         out[2]= in[2];
00302                         out[3]= 1.0f;
00303                 }
00304         }
00305 }
00306 
00307 CompBuf *typecheck_compbuf(CompBuf *inbuf, int type)
00308 {
00309         if(inbuf && inbuf->type!=type) {
00310                 CompBuf *outbuf;
00311                 float *inrf, *outrf;
00312                 int x;
00313 
00314                 outbuf= alloc_compbuf(inbuf->x, inbuf->y, type, 1); 
00315 
00316                 /* warning note: xof and yof are applied in pixelprocessor, but should be copied otherwise? */
00317                 outbuf->xof= inbuf->xof;
00318                 outbuf->yof= inbuf->yof;
00319 
00320                 if(inbuf->rect_procedural) {
00321                         outbuf->rect_procedural= inbuf->rect_procedural;
00322                         VECCOPY(outbuf->procedural_size, inbuf->procedural_size);
00323                         VECCOPY(outbuf->procedural_offset, inbuf->procedural_offset);
00324                         outbuf->procedural_type= inbuf->procedural_type;
00325                         outbuf->node= inbuf->node;
00326                         return outbuf;
00327                 }
00328 
00329                 inrf= inbuf->rect;
00330                 outrf= outbuf->rect;
00331                 x= inbuf->x*inbuf->y;
00332                 
00333                 if(type==CB_VAL) {
00334                         if(inbuf->type==CB_VEC2) {
00335                                 for(; x>0; x--, outrf+= 1, inrf+= 2)
00336                                         *outrf= 0.5f*(inrf[0]+inrf[1]);
00337                         }
00338                         else if(inbuf->type==CB_VEC3) {
00339                                 for(; x>0; x--, outrf+= 1, inrf+= 3)
00340                                         *outrf= 0.333333f*(inrf[0]+inrf[1]+inrf[2]);
00341                         }
00342                         else if(inbuf->type==CB_RGBA) {
00343                                 for(; x>0; x--, outrf+= 1, inrf+= 4)
00344                                         *outrf= inrf[0]*0.35f + inrf[1]*0.45f + inrf[2]*0.2f;
00345                         }
00346                 }
00347                 else if(type==CB_VEC2) {
00348                         if(inbuf->type==CB_VAL) {
00349                                 for(; x>0; x--, outrf+= 2, inrf+= 1) {
00350                                         outrf[0]= inrf[0];
00351                                         outrf[1]= inrf[0];
00352                                 }
00353                         }
00354                         else if(inbuf->type==CB_VEC3) {
00355                                 for(; x>0; x--, outrf+= 2, inrf+= 3) {
00356                                         outrf[0]= inrf[0];
00357                                         outrf[1]= inrf[1];
00358                                 }
00359                         }
00360                         else if(inbuf->type==CB_RGBA) {
00361                                 for(; x>0; x--, outrf+= 2, inrf+= 4) {
00362                                         outrf[0]= inrf[0];
00363                                         outrf[1]= inrf[1];
00364                                 }
00365                         }
00366                 }
00367                 else if(type==CB_VEC3) {
00368                         if(inbuf->type==CB_VAL) {
00369                                 for(; x>0; x--, outrf+= 3, inrf+= 1) {
00370                                         outrf[0]= inrf[0];
00371                                         outrf[1]= inrf[0];
00372                                         outrf[2]= inrf[0];
00373                                 }
00374                         }
00375                         else if(inbuf->type==CB_VEC2) {
00376                                 for(; x>0; x--, outrf+= 3, inrf+= 2) {
00377                                         outrf[0]= inrf[0];
00378                                         outrf[1]= inrf[1];
00379                                         outrf[2]= 0.0f;
00380                                 }
00381                         }
00382                         else if(inbuf->type==CB_RGBA) {
00383                                 for(; x>0; x--, outrf+= 3, inrf+= 4) {
00384                                         outrf[0]= inrf[0];
00385                                         outrf[1]= inrf[1];
00386                                         outrf[2]= inrf[2];
00387                                 }
00388                         }
00389                 }
00390                 else if(type==CB_RGBA) {
00391                         if(inbuf->type==CB_VAL) {
00392                                 for(; x>0; x--, outrf+= 4, inrf+= 1) {
00393                                         outrf[0]= inrf[0];
00394                                         outrf[1]= inrf[0];
00395                                         outrf[2]= inrf[0];
00396                                         outrf[3]= 1.0f;
00397                                 }
00398                         }
00399                         else if(inbuf->type==CB_VEC2) {
00400                                 for(; x>0; x--, outrf+= 4, inrf+= 2) {
00401                                         outrf[0]= inrf[0];
00402                                         outrf[1]= inrf[1];
00403                                         outrf[2]= 0.0f;
00404                                         outrf[3]= 1.0f;
00405                                 }
00406                         }
00407                         else if(inbuf->type==CB_VEC3) {
00408                                 for(; x>0; x--, outrf+= 4, inrf+= 3) {
00409                                         outrf[0]= inrf[0];
00410                                         outrf[1]= inrf[1];
00411                                         outrf[2]= inrf[2];
00412                                         outrf[3]= 1.0f;
00413                                 }
00414                         }
00415                 }
00416                 
00417                 return outbuf;
00418         }
00419         return inbuf;
00420 }
00421 
00422 static float *compbuf_get_pixel(CompBuf *cbuf, float *defcol, float *use, int x, int y, int xrad, int yrad)
00423 {
00424         if(cbuf) {
00425                 if(cbuf->rect_procedural) {
00426                         cbuf->rect_procedural(cbuf, use, (float)x/(float)xrad, (float)y/(float)yrad);
00427                         return use;
00428                 }
00429                 else {
00430                         static float col[4]= {0.0f, 0.0f, 0.0f, 0.0f};
00431                         
00432                         /* map coords */
00433                         x-= cbuf->xof;
00434                         y-= cbuf->yof;
00435                         
00436                         if(y<-cbuf->yrad || y>= -cbuf->yrad+cbuf->y) return col;
00437                         if(x<-cbuf->xrad || x>= -cbuf->xrad+cbuf->x) return col;
00438                         
00439                         return cbuf->rect + cbuf->type*( (cbuf->yrad+y)*cbuf->x + (cbuf->xrad+x) );
00440                 }
00441         }
00442         else return defcol;
00443 }
00444 
00445 /* **************************************************** */
00446 
00447 /* Pixel-to-Pixel operation, 1 Image in, 1 out */
00448 void composit1_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
00449                                                                           void (*func)(bNode *, float *, float *), 
00450                                                                           int src_type)
00451 {
00452         CompBuf *src_use;
00453         float *outfp=out->rect, *srcfp;
00454         float color[4]; /* local color if compbuf is procedural */
00455         int xrad, yrad, x, y;
00456         
00457         src_use= typecheck_compbuf(src_buf, src_type);
00458         
00459         xrad= out->xrad;
00460         yrad= out->yrad;
00461         
00462         for(y= -yrad; y<-yrad+out->y; y++) {
00463                 for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) {
00464                         srcfp= compbuf_get_pixel(src_use, src_col, color, x, y, xrad, yrad);
00465                         func(node, outfp, srcfp);
00466                 }
00467         }
00468         
00469         if(src_use!=src_buf)
00470                 free_compbuf(src_use);
00471 }
00472 
00473 /* Pixel-to-Pixel operation, 2 Images in, 1 out */
00474 void composit2_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
00475                                                                           CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *), 
00476                                                                           int src_type, int fac_type)
00477 {
00478         CompBuf *src_use, *fac_use;
00479         float *outfp=out->rect, *srcfp, *facfp;
00480         float color[4]; /* local color if compbuf is procedural */
00481         int xrad, yrad, x, y;
00482         
00483         src_use= typecheck_compbuf(src_buf, src_type);
00484         fac_use= typecheck_compbuf(fac_buf, fac_type);
00485 
00486         xrad= out->xrad;
00487         yrad= out->yrad;
00488         
00489         for(y= -yrad; y<-yrad+out->y; y++) {
00490                 for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) {
00491                         srcfp= compbuf_get_pixel(src_use, src_col, color, x, y, xrad, yrad);
00492                         facfp= compbuf_get_pixel(fac_use, fac, color, x, y, xrad, yrad);
00493                         
00494                         func(node, outfp, srcfp, facfp);
00495                 }
00496         }
00497         if(src_use!=src_buf)
00498                 free_compbuf(src_use);
00499         if(fac_use!=fac_buf)
00500                 free_compbuf(fac_use);
00501 }
00502 
00503 /* Pixel-to-Pixel operation, 3 Images in, 1 out */
00504 void composit3_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *src2_buf, float *src2_col, 
00505                                                                           CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *, float *), 
00506                                                                           int src1_type, int src2_type, int fac_type)
00507 {
00508         CompBuf *src1_use, *src2_use, *fac_use;
00509         float *outfp=out->rect, *src1fp, *src2fp, *facfp;
00510         float color[4]; /* local color if compbuf is procedural */
00511         int xrad, yrad, x, y;
00512         
00513         src1_use= typecheck_compbuf(src1_buf, src1_type);
00514         src2_use= typecheck_compbuf(src2_buf, src2_type);
00515         fac_use= typecheck_compbuf(fac_buf, fac_type);
00516         
00517         xrad= out->xrad;
00518         yrad= out->yrad;
00519         
00520         for(y= -yrad; y<-yrad+out->y; y++) {
00521                 for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) {
00522                         src1fp= compbuf_get_pixel(src1_use, src1_col, color, x, y, xrad, yrad);
00523                         src2fp= compbuf_get_pixel(src2_use, src2_col, color, x, y, xrad, yrad);
00524                         facfp= compbuf_get_pixel(fac_use, fac, color, x, y, xrad, yrad);
00525                         
00526                         func(node, outfp, src1fp, src2fp, facfp);
00527                 }
00528         }
00529         
00530         if(src1_use!=src1_buf)
00531                 free_compbuf(src1_use);
00532         if(src2_use!=src2_buf)
00533                 free_compbuf(src2_use);
00534         if(fac_use!=fac_buf)
00535                 free_compbuf(fac_use);
00536 }
00537 
00538 /* Pixel-to-Pixel operation, 4 Images in, 1 out */
00539 void composit4_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *fac1_buf, float *fac1, 
00540                                                                           CompBuf *src2_buf, float *src2_col, CompBuf *fac2_buf, float *fac2, 
00541                                                                           void (*func)(bNode *, float *, float *, float *, float *, float *), 
00542                                                                           int src1_type, int fac1_type, int src2_type, int fac2_type)
00543 {
00544         CompBuf *src1_use, *src2_use, *fac1_use, *fac2_use;
00545         float *outfp=out->rect, *src1fp, *src2fp, *fac1fp, *fac2fp;
00546         float color[4]; /* local color if compbuf is procedural */
00547         int xrad, yrad, x, y;
00548         
00549         src1_use= typecheck_compbuf(src1_buf, src1_type);
00550         src2_use= typecheck_compbuf(src2_buf, src2_type);
00551         fac1_use= typecheck_compbuf(fac1_buf, fac1_type);
00552         fac2_use= typecheck_compbuf(fac2_buf, fac2_type);
00553         
00554         xrad= out->xrad;
00555         yrad= out->yrad;
00556         
00557         for(y= -yrad; y<-yrad+out->y; y++) {
00558                 for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) {
00559                         src1fp= compbuf_get_pixel(src1_use, src1_col, color, x, y, xrad, yrad);
00560                         src2fp= compbuf_get_pixel(src2_use, src2_col, color, x, y, xrad, yrad);
00561                         fac1fp= compbuf_get_pixel(fac1_use, fac1, color, x, y, xrad, yrad);
00562                         fac2fp= compbuf_get_pixel(fac2_use, fac2, color, x, y, xrad, yrad);
00563                         
00564                         func(node, outfp, src1fp, fac1fp, src2fp, fac2fp);
00565                 }
00566         }
00567         
00568         if(src1_use!=src1_buf)
00569                 free_compbuf(src1_use);
00570         if(src2_use!=src2_buf)
00571                 free_compbuf(src2_use);
00572         if(fac1_use!=fac1_buf)
00573                 free_compbuf(fac1_use);
00574         if(fac2_use!=fac2_buf)
00575                 free_compbuf(fac2_use);
00576 }
00577 
00578 
00579 CompBuf *valbuf_from_rgbabuf(CompBuf *cbuf, int channel)
00580 {
00581         CompBuf *valbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);
00582         float *valf, *rectf;
00583         int tot;
00584         
00585         /* warning note: xof and yof are applied in pixelprocessor, but should be copied otherwise? */
00586         valbuf->xof= cbuf->xof;
00587         valbuf->yof= cbuf->yof;
00588         
00589         valf= valbuf->rect;
00590 
00591         /* defaults to returning alpha channel */
00592         if ((channel < CHAN_R) || (channel > CHAN_A)) channel = CHAN_A;
00593 
00594         rectf= cbuf->rect + channel;
00595         
00596         for(tot= cbuf->x*cbuf->y; tot>0; tot--, valf++, rectf+=4)
00597                 *valf= *rectf;
00598         
00599         return valbuf;
00600 }
00601 
00602 static CompBuf *generate_procedural_preview(CompBuf *cbuf, int newx, int newy)
00603 {
00604         CompBuf *outbuf;
00605         float *outfp;
00606         int xrad, yrad, x, y;
00607         
00608         outbuf= alloc_compbuf(newx, newy, CB_RGBA, 1);
00609 
00610         outfp= outbuf->rect;
00611         xrad= outbuf->xrad;
00612         yrad= outbuf->yrad;
00613         
00614         for(y= -yrad; y<-yrad+outbuf->y; y++)
00615                 for(x= -xrad; x<-xrad+outbuf->x; x++, outfp+=outbuf->type)
00616                         cbuf->rect_procedural(cbuf, outfp, (float)x/(float)xrad, (float)y/(float)yrad);
00617 
00618         return outbuf;
00619 }
00620 
00621 void generate_preview(void *data, bNode *node, CompBuf *stackbuf)
00622 {
00623         RenderData *rd= data;
00624         bNodePreview *preview= node->preview;
00625         int xsize, ysize;
00626         int color_manage= rd->color_mgt_flag & R_COLOR_MANAGEMENT;
00627         unsigned char *rect;
00628         
00629         if(preview && stackbuf) {
00630                 CompBuf *cbuf, *stackbuf_use;
00631                 
00632                 if(stackbuf->rect==NULL && stackbuf->rect_procedural==NULL) return;
00633                 
00634                 stackbuf_use= typecheck_compbuf(stackbuf, CB_RGBA);
00635 
00636                 if(stackbuf->x > stackbuf->y) {
00637                         xsize= 140;
00638                         ysize= (140*stackbuf->y)/stackbuf->x;
00639                 }
00640                 else {
00641                         ysize= 140;
00642                         xsize= (140*stackbuf->x)/stackbuf->y;
00643                 }
00644                 
00645                 if(stackbuf_use->rect_procedural)
00646                         cbuf= generate_procedural_preview(stackbuf_use, xsize, ysize);
00647                 else
00648                         cbuf= scalefast_compbuf(stackbuf_use, xsize, ysize);
00649 
00650                 /* convert to byte for preview */
00651                 rect= MEM_callocN(sizeof(unsigned char)*4*xsize*ysize, "bNodePreview.rect");
00652 
00653                 if(color_manage)
00654                         floatbuf_to_srgb_byte(cbuf->rect, rect, 0, xsize, 0, ysize, xsize);
00655                 else
00656                         floatbuf_to_byte(cbuf->rect, rect, 0, xsize, 0, ysize, xsize);
00657                 
00658                 free_compbuf(cbuf);
00659                 if(stackbuf_use!=stackbuf)
00660                         free_compbuf(stackbuf_use);
00661 
00662                 BLI_lock_thread(LOCK_PREVIEW);
00663 
00664                 if(preview->rect)
00665                         MEM_freeN(preview->rect);
00666                 preview->xsize= xsize;
00667                 preview->ysize= ysize;
00668                 preview->rect= rect;
00669 
00670                 BLI_unlock_thread(LOCK_PREVIEW);
00671         }
00672 }
00673 
00674 void do_rgba_to_yuva(bNode *UNUSED(node), float *out, float *in)
00675 {
00676         rgb_to_yuv(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
00677         out[3]=in[3];
00678 }
00679 
00680 void do_rgba_to_hsva(bNode *UNUSED(node), float *out, float *in)
00681 {
00682         rgb_to_hsv(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
00683         out[3]=in[3];
00684 }
00685 
00686 void do_rgba_to_ycca(bNode *UNUSED(node), float *out, float *in)
00687 {
00688         rgb_to_ycc(in[0],in[1],in[2], &out[0], &out[1], &out[2], BLI_YCC_ITU_BT601);
00689         out[3]=in[3];
00690 }
00691 
00692 void do_yuva_to_rgba(bNode *UNUSED(node), float *out, float *in)
00693 {
00694         yuv_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
00695         out[3]=in[3];
00696 }
00697 
00698 void do_hsva_to_rgba(bNode *UNUSED(node), float *out, float *in)
00699 {
00700         hsv_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
00701         out[3]=in[3];
00702 }
00703 
00704 void do_ycca_to_rgba(bNode *UNUSED(node), float *out, float *in)
00705 {
00706         ycc_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2], BLI_YCC_ITU_BT601);
00707         out[3]=in[3];
00708 }
00709 
00710 void do_copy_rgba(bNode *UNUSED(node), float *out, float *in)
00711 {
00712         QUATCOPY(out, in);
00713 }
00714 
00715 void do_copy_rgb(bNode *UNUSED(node), float *out, float *in)
00716 {
00717         VECCOPY(out, in);
00718         out[3]= 1.0f;
00719 }
00720 
00721 void do_copy_value(bNode *UNUSED(node), float *out, float *in)
00722 {
00723         out[0]= in[0];
00724 }
00725 
00726 void do_copy_a_rgba(bNode *UNUSED(node), float *out, float *in, float *fac)
00727 {
00728         VECCOPY(out, in);
00729         out[3]= *fac;
00730 }
00731 
00732 /* only accepts RGBA buffers */
00733 void gamma_correct_compbuf(CompBuf *img, int inversed)
00734 {
00735         float *drect;
00736         int x;
00737 
00738         if(img->type!=CB_RGBA) return;
00739 
00740         drect= img->rect;
00741         if(inversed) {
00742                 for(x=img->x*img->y; x>0; x--, drect+=4) {
00743                         if(drect[0]>0.0f) drect[0]= sqrt(drect[0]); else drect[0]= 0.0f;
00744                         if(drect[1]>0.0f) drect[1]= sqrt(drect[1]); else drect[1]= 0.0f;
00745                         if(drect[2]>0.0f) drect[2]= sqrt(drect[2]); else drect[2]= 0.0f;
00746                 }
00747         }
00748         else {
00749                 for(x=img->x*img->y; x>0; x--, drect+=4) {
00750                         if(drect[0]>0.0f) drect[0]*= drect[0]; else drect[0]= 0.0f;
00751                         if(drect[1]>0.0f) drect[1]*= drect[1]; else drect[1]= 0.0f;
00752                         if(drect[2]>0.0f) drect[2]*= drect[2]; else drect[2]= 0.0f;
00753                 }
00754         }
00755 }
00756 
00757 void premul_compbuf(CompBuf *img, int inversed)
00758 {
00759         float *drect;
00760         int x;
00761 
00762         if(img->type!=CB_RGBA) return;
00763 
00764         drect= img->rect;
00765         if(inversed) {
00766                 for(x=img->x*img->y; x>0; x--, drect+=4) {
00767                         if(fabs(drect[3]) < 1e-5f) {
00768                                 drect[0]= 0.0f;
00769                                 drect[1]= 0.0f;
00770                                 drect[2]= 0.0f;
00771                         }
00772                         else {
00773                                 drect[0] /= drect[3];
00774                                 drect[1] /= drect[3];
00775                                 drect[2] /= drect[3];
00776                         }
00777                 }
00778         }
00779         else {
00780                 for(x=img->x*img->y; x>0; x--, drect+=4) {
00781                         drect[0] *= drect[3];
00782                         drect[1] *= drect[3];
00783                         drect[2] *= drect[3];
00784                 }
00785         }
00786 }
00787 
00788 
00789 
00790 /*
00791  *  2D Fast Hartley Transform, used for convolution
00792  */
00793 
00794 typedef float fREAL;
00795 
00796 // returns next highest power of 2 of x, as well it's log2 in L2
00797 static unsigned int nextPow2(unsigned int x, unsigned int* L2)
00798 {
00799         unsigned int pw, x_notpow2 = x & (x-1);
00800         *L2 = 0;
00801         while (x>>=1) ++(*L2);
00802         pw = 1 << (*L2);
00803         if (x_notpow2) { (*L2)++;  pw<<=1; }
00804         return pw;
00805 }
00806 
00807 //------------------------------------------------------------------------------
00808 
00809 // from FXT library by Joerg Arndt, faster in order bitreversal
00810 // use: r = revbin_upd(r, h) where h = N>>1
00811 static unsigned int revbin_upd(unsigned int r, unsigned int h)
00812 {
00813         while (!((r^=h)&h)) h >>= 1;
00814         return r;
00815 }
00816 //------------------------------------------------------------------------------
00817 static void FHT(fREAL* data, unsigned int M, unsigned int inverse)
00818 {
00819         double tt, fc, dc, fs, ds, a = M_PI;
00820         fREAL t1, t2;
00821         int n2, bd, bl, istep, k, len = 1 << M, n = 1;
00822 
00823         int i, j = 0;
00824         unsigned int Nh = len >> 1;
00825         for (i=1;i<(len-1);++i) {
00826                 j = revbin_upd(j, Nh);
00827                 if (j>i) {
00828                         t1 = data[i];
00829                         data[i] = data[j];
00830                         data[j] = t1;
00831                 }
00832         }
00833 
00834         do {
00835                 fREAL* data_n = &data[n];
00836 
00837                 istep = n << 1;
00838                 for (k=0; k<len; k+=istep) {
00839                         t1 = data_n[k];
00840                         data_n[k] = data[k] - t1;
00841                         data[k] += t1;
00842                 }
00843 
00844                 n2 = n >> 1;
00845                 if (n>2) {
00846                         fc = dc = cos(a);
00847                         fs = ds = sqrt(1.0 - fc*fc); //sin(a);
00848                         bd = n-2;
00849                         for (bl=1; bl<n2; bl++) {
00850                                 fREAL* data_nbd = &data_n[bd];
00851                                 fREAL* data_bd = &data[bd];
00852                                 for (k=bl; k<len; k+=istep) {
00853                                         t1 = fc*data_n[k] + fs*data_nbd[k];
00854                                         t2 = fs*data_n[k] - fc*data_nbd[k];
00855                                         data_n[k] = data[k] - t1;
00856                                         data_nbd[k] = data_bd[k] - t2;
00857                                         data[k] += t1;
00858                                         data_bd[k] += t2;
00859                                 }
00860                                 tt = fc*dc - fs*ds;
00861                                 fs = fs*dc + fc*ds;
00862                                 fc = tt;
00863                                 bd -= 2;
00864                         }
00865                 }
00866 
00867                 if (n>1) {
00868                         for (k=n2; k<len; k+=istep) {
00869                                 t1 = data_n[k];
00870                                 data_n[k] = data[k] - t1;
00871                                 data[k] += t1;
00872                         }
00873                 }
00874 
00875                 n = istep;
00876                 a *= 0.5;
00877         } while (n<len);
00878 
00879         if (inverse) {
00880                 fREAL sc = (fREAL)1 / (fREAL)len;
00881                 for (k=0; k<len; ++k)
00882                         data[k] *= sc;
00883         }
00884 }
00885 //------------------------------------------------------------------------------
00886 /* 2D Fast Hartley Transform, Mx/My -> log2 of width/height,
00887         nzp -> the row where zero pad data starts,
00888         inverse -> see above */
00889 static void FHT2D(fREAL *data, unsigned int Mx, unsigned int My,
00890                 unsigned int nzp, unsigned int inverse)
00891 {
00892         unsigned int i, j, Nx, Ny, maxy;
00893         fREAL t;
00894 
00895         Nx = 1 << Mx;
00896         Ny = 1 << My;
00897 
00898         // rows (forward transform skips 0 pad data)
00899         maxy = inverse ? Ny : nzp;
00900         for (j=0; j<maxy; ++j)
00901                 FHT(&data[Nx*j], Mx, inverse);
00902 
00903         // transpose data
00904         if (Nx==Ny) {  // square
00905                 for (j=0; j<Ny; ++j)
00906                         for (i=j+1; i<Nx; ++i) {
00907                                 unsigned int op = i + (j << Mx), np = j + (i << My);
00908                                 t=data[op], data[op]=data[np], data[np]=t;
00909                         }
00910         }
00911         else {  // rectangular
00912                 unsigned int k, Nym = Ny-1, stm = 1 << (Mx + My);
00913                 for (i=0; stm>0; i++) {
00914                         #define pred(k) (((k & Nym) << Mx) + (k >> My))
00915                         for (j=pred(i); j>i; j=pred(j));
00916                         if (j < i) continue;
00917                         for (k=i, j=pred(i); j!=i; k=j, j=pred(j), stm--)
00918                                 { t=data[j], data[j]=data[k], data[k]=t; }
00919                         #undef pred
00920                         stm--;
00921                 }
00922         }
00923         // swap Mx/My & Nx/Ny
00924         i = Nx, Nx = Ny, Ny = i;
00925         i = Mx, Mx = My, My = i;
00926 
00927         // now columns == transposed rows
00928         for (j=0; j<Ny; ++j)
00929                 FHT(&data[Nx*j], Mx, inverse);
00930 
00931         // finalize
00932         for (j=0; j<=(Ny >> 1); j++) {
00933                 unsigned int jm = (Ny - j) & (Ny-1);
00934                 unsigned int ji = j << Mx;
00935                 unsigned int jmi = jm << Mx;
00936                 for (i=0; i<=(Nx >> 1); i++) {
00937                         unsigned int im = (Nx - i) & (Nx-1);
00938                         fREAL A = data[ji + i];
00939                         fREAL B = data[jmi + i];
00940                         fREAL C = data[ji + im];
00941                         fREAL D = data[jmi + im];
00942                         fREAL E = (fREAL)0.5*((A + D) - (B + C));
00943                         data[ji + i] = A - E;
00944                         data[jmi + i] = B + E;
00945                         data[ji + im] = C + E;
00946                         data[jmi + im] = D - E;
00947                 }
00948         }
00949 
00950 }
00951 
00952 //------------------------------------------------------------------------------
00953 
00954 /* 2D convolution calc, d1 *= d2, M/N - > log2 of width/height */
00955 static void fht_convolve(fREAL* d1, fREAL* d2, unsigned int M, unsigned int N)
00956 {
00957         fREAL a, b;
00958         unsigned int i, j, k, L, mj, mL;
00959         unsigned int m = 1 << M, n = 1 << N;
00960         unsigned int m2 = 1 << (M-1), n2 = 1 << (N-1);
00961         unsigned int mn2 = m << (N-1);
00962 
00963         d1[0] *= d2[0];
00964         d1[mn2] *= d2[mn2];
00965         d1[m2] *= d2[m2];
00966         d1[m2 + mn2] *= d2[m2 + mn2];
00967         for (i=1; i<m2; i++) {
00968                 k = m - i;
00969                 a = d1[i]*d2[i] - d1[k]*d2[k];
00970                 b = d1[k]*d2[i] + d1[i]*d2[k];
00971                 d1[i] = (b + a)*(fREAL)0.5;
00972                 d1[k] = (b - a)*(fREAL)0.5;
00973                 a = d1[i + mn2]*d2[i + mn2] - d1[k + mn2]*d2[k + mn2];
00974                 b = d1[k + mn2]*d2[i + mn2] + d1[i + mn2]*d2[k + mn2];
00975                 d1[i + mn2] = (b + a)*(fREAL)0.5;
00976                 d1[k + mn2] = (b - a)*(fREAL)0.5;
00977         }
00978         for (j=1; j<n2; j++) {
00979                 L = n - j;
00980                 mj = j << M;
00981                 mL = L << M;
00982                 a = d1[mj]*d2[mj] - d1[mL]*d2[mL];
00983                 b = d1[mL]*d2[mj] + d1[mj]*d2[mL];
00984                 d1[mj] = (b + a)*(fREAL)0.5;
00985                 d1[mL] = (b - a)*(fREAL)0.5;
00986                 a = d1[m2 + mj]*d2[m2 + mj] - d1[m2 + mL]*d2[m2 + mL];
00987                 b = d1[m2 + mL]*d2[m2 + mj] + d1[m2 + mj]*d2[m2 + mL];
00988                 d1[m2 + mj] = (b + a)*(fREAL)0.5;
00989                 d1[m2 + mL] = (b - a)*(fREAL)0.5;
00990         }
00991         for (i=1; i<m2; i++) {
00992                 k = m - i;
00993                 for (j=1; j<n2; j++) {
00994                         L = n - j;
00995                         mj = j << M;
00996                         mL = L << M;
00997                         a = d1[i + mj]*d2[i + mj] - d1[k + mL]*d2[k + mL];
00998                         b = d1[k + mL]*d2[i + mj] + d1[i + mj]*d2[k + mL];
00999                         d1[i + mj] = (b + a)*(fREAL)0.5;
01000                         d1[k + mL] = (b - a)*(fREAL)0.5;
01001                         a = d1[i + mL]*d2[i + mL] - d1[k + mj]*d2[k + mj];
01002                         b = d1[k + mj]*d2[i + mL] + d1[i + mL]*d2[k + mj];
01003                         d1[i + mL] = (b + a)*(fREAL)0.5;
01004                         d1[k + mj] = (b - a)*(fREAL)0.5;
01005                 }
01006         }
01007 }
01008 
01009 //------------------------------------------------------------------------------
01010 
01011 void convolve(CompBuf* dst, CompBuf* in1, CompBuf* in2)
01012 {
01013         fREAL *data1, *data2, *fp;
01014         unsigned int w2, h2, hw, hh, log2_w, log2_h;
01015         fRGB wt, *colp;
01016         int x, y, ch;
01017         int xbl, ybl, nxb, nyb, xbsz, ybsz;
01018         int in2done = 0;
01019 
01020         CompBuf* rdst = alloc_compbuf(in1->x, in1->y, in1->type, 1);
01021 
01022         // convolution result width & height
01023         w2 = 2*in2->x - 1;
01024         h2 = 2*in2->y - 1;
01025         // FFT pow2 required size & log2
01026         w2 = nextPow2(w2, &log2_w);
01027         h2 = nextPow2(h2, &log2_h);
01028 
01029         // alloc space
01030         data1 = (fREAL*)MEM_callocN(3*w2*h2*sizeof(fREAL), "convolve_fast FHT data1");
01031         data2 = (fREAL*)MEM_callocN(w2*h2*sizeof(fREAL), "convolve_fast FHT data2");
01032 
01033         // normalize convolutor
01034         wt[0] = wt[1] = wt[2] = 0.f;
01035         for (y=0; y<in2->y; y++) {
01036                 colp = (fRGB*)&in2->rect[y*in2->x*in2->type];
01037                 for (x=0; x<in2->x; x++)
01038                         fRGB_add(wt, colp[x]);
01039         }
01040         if (wt[0] != 0.f) wt[0] = 1.f/wt[0];
01041         if (wt[1] != 0.f) wt[1] = 1.f/wt[1];
01042         if (wt[2] != 0.f) wt[2] = 1.f/wt[2];
01043         for (y=0; y<in2->y; y++) {
01044                 colp = (fRGB*)&in2->rect[y*in2->x*in2->type];
01045                 for (x=0; x<in2->x; x++)
01046                         fRGB_colormult(colp[x], wt);
01047         }
01048 
01049         // copy image data, unpacking interleaved RGBA into separate channels
01050         // only need to calc data1 once
01051 
01052         // block add-overlap
01053         hw = in2->x >> 1;
01054         hh = in2->y >> 1;
01055         xbsz = (w2 + 1) - in2->x;
01056         ybsz = (h2 + 1) - in2->y;
01057         nxb = in1->x / xbsz;
01058         if (in1->x % xbsz) nxb++;
01059         nyb = in1->y / ybsz;
01060         if (in1->y % ybsz) nyb++;
01061         for (ybl=0; ybl<nyb; ybl++) {
01062                 for (xbl=0; xbl<nxb; xbl++) {
01063 
01064                         // each channel one by one
01065                         for (ch=0; ch<3; ch++) {
01066                                 fREAL* data1ch = &data1[ch*w2*h2];
01067 
01068                                 // only need to calc fht data from in2 once, can re-use for every block
01069                                 if (!in2done) {
01070                                         // in2, channel ch -> data1
01071                                         for (y=0; y<in2->y; y++) {
01072                                                 fp = &data1ch[y*w2];
01073                                                 colp = (fRGB*)&in2->rect[y*in2->x*in2->type];
01074                                                 for (x=0; x<in2->x; x++)
01075                                                         fp[x] = colp[x][ch];
01076                                         }
01077                                 }
01078 
01079                                 // in1, channel ch -> data2
01080                                 memset(data2, 0, w2*h2*sizeof(fREAL));
01081                                 for (y=0; y<ybsz; y++) {
01082                                         int yy = ybl*ybsz + y;
01083                                         if (yy >= in1->y) continue;
01084                                         fp = &data2[y*w2];
01085                                         colp = (fRGB*)&in1->rect[yy*in1->x*in1->type];
01086                                         for (x=0; x<xbsz; x++) {
01087                                                 int xx = xbl*xbsz + x;
01088                                                 if (xx >= in1->x) continue;
01089                                                 fp[x] = colp[xx][ch];
01090                                         }
01091                                 }
01092 
01093                                 // forward FHT
01094                                 // zero pad data start is different for each == height+1
01095                                 if (!in2done) FHT2D(data1ch, log2_w, log2_h, in2->y+1, 0);
01096                                 FHT2D(data2, log2_w, log2_h, in2->y+1, 0);
01097 
01098                                 // FHT2D transposed data, row/col now swapped
01099                                 // convolve & inverse FHT
01100                                 fht_convolve(data2, data1ch, log2_h, log2_w);
01101                                 FHT2D(data2, log2_h, log2_w, 0, 1);
01102                                 // data again transposed, so in order again
01103 
01104                                 // overlap-add result
01105                                 for (y=0; y<(int)h2; y++) {
01106                                         const int yy = ybl*ybsz + y - hh;
01107                                         if ((yy < 0) || (yy >= in1->y)) continue;
01108                                         fp = &data2[y*w2];
01109                                         colp = (fRGB*)&rdst->rect[yy*in1->x*in1->type];
01110                                         for (x=0; x<(int)w2; x++) {
01111                                                 const int xx = xbl*xbsz + x - hw;
01112                                                 if ((xx < 0) || (xx >= in1->x)) continue;
01113                                                 colp[xx][ch] += fp[x];
01114                                         }
01115                                 }
01116 
01117                         }
01118                         in2done = 1;
01119                 }
01120         }
01121 
01122         MEM_freeN(data2);
01123         MEM_freeN(data1);
01124         memcpy(dst->rect, rdst->rect, sizeof(float)*dst->x*dst->y*dst->type);
01125         free_compbuf(rdst);
01126 }
01127 
01128 
01129 /*
01130  *
01131  * Utility functions qd_* should probably be intergrated better with other functions here.
01132  *
01133  */
01134 // sets fcol to pixelcolor at (x, y)
01135 void qd_getPixel(CompBuf* src, int x, int y, float* col)
01136 {
01137         if(src->rect_procedural) {
01138                 float bc[4];
01139                 src->rect_procedural(src, bc, (float)x/(float)src->xrad, (float)y/(float)src->yrad);
01140 
01141                 switch(src->type){
01142                         /* these fallthrough to get all the channels */
01143                         case CB_RGBA: col[3]=bc[3]; 
01144                         case CB_VEC3: col[2]=bc[2];
01145                         case CB_VEC2: col[1]=bc[1];
01146                         case CB_VAL: col[0]=bc[0];
01147                 }
01148         }
01149         else if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) {
01150                 float* bc = &src->rect[(x + y*src->x)*src->type];
01151                 switch(src->type){
01152                         /* these fallthrough to get all the channels */
01153                         case CB_RGBA: col[3]=bc[3]; 
01154                         case CB_VEC3: col[2]=bc[2];
01155                         case CB_VEC2: col[1]=bc[1];
01156                         case CB_VAL: col[0]=bc[0];
01157                 }
01158         }
01159         else {
01160                 switch(src->type){
01161                         /* these fallthrough to get all the channels */
01162                         case CB_RGBA: col[3]=0.0; 
01163                         case CB_VEC3: col[2]=0.0; 
01164                         case CB_VEC2: col[1]=0.0; 
01165                         case CB_VAL: col[0]=0.0; 
01166                 }
01167         }
01168 }
01169 
01170 // sets pixel (x, y) to color col
01171 void qd_setPixel(CompBuf* src, int x, int y, float* col)
01172 {
01173         if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) {
01174                 float* bc = &src->rect[(x + y*src->x)*src->type];
01175                 switch(src->type){
01176                         /* these fallthrough to get all the channels */
01177                         case CB_RGBA: bc[3]=col[3]; 
01178                         case CB_VEC3: bc[2]=col[2];
01179                         case CB_VEC2: bc[1]=col[1];
01180                         case CB_VAL: bc[0]=col[0];
01181                 }
01182         }
01183 }
01184 
01185 // adds fcol to pixelcolor (x, y)
01186 void qd_addPixel(CompBuf* src, int x, int y, float* col)
01187 {
01188         if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) {
01189                 float* bc = &src->rect[(x + y*src->x)*src->type];
01190                 bc[0] += col[0], bc[1] += col[1], bc[2] += col[2];
01191         }
01192 }
01193 
01194 // multiplies pixel by factor value f
01195 void qd_multPixel(CompBuf* src, int x, int y, float f)
01196 {
01197         if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) {
01198                 float* bc = &src->rect[(x + y*src->x)*src->type];
01199                 bc[0] *= f, bc[1] *= f, bc[2] *= f;
01200         }
01201 }
01202 
01203 // bilinear interpolation with wraparound
01204 void qd_getPixelLerpWrap(CompBuf* src, float u, float v, float* col)
01205 {
01206         const float ufl = floor(u), vfl = floor(v);
01207         const int nx = (int)ufl % src->x, ny = (int)vfl % src->y;
01208         const int x1 = (nx < 0) ? (nx + src->x) : nx;
01209         const int y1 = (ny < 0) ? (ny + src->y) : ny;
01210         const int x2 = (x1 + 1) % src->x, y2 = (y1 + 1) % src->y;
01211         const float* c00 = &src->rect[(x1 + y1*src->x)*src->type];
01212         const float* c10 = &src->rect[(x2 + y1*src->x)*src->type];
01213         const float* c01 = &src->rect[(x1 + y2*src->x)*src->type];
01214         const float* c11 = &src->rect[(x2 + y2*src->x)*src->type];
01215         const float uf = u - ufl, vf = v - vfl;
01216         const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf;
01217         col[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0];
01218         if (src->type != CB_VAL) {
01219                 col[1] = w00*c00[1] + w10*c10[1] + w01*c01[1] + w11*c11[1];
01220                 col[2] = w00*c00[2] + w10*c10[2] + w01*c01[2] + w11*c11[2];
01221                 col[3] = w00*c00[3] + w10*c10[3] + w01*c01[3] + w11*c11[3];
01222         }
01223 }
01224 
01225 // as above, without wrap around
01226 void qd_getPixelLerp(CompBuf* src, float u, float v, float* col)
01227 {
01228         const float ufl = floor(u), vfl = floor(v);
01229         const int x1 = (int)ufl, y1 = (int)vfl;
01230         const int x2 = (int)ceil(u), y2 = (int)ceil(v);
01231         if ((x2 >= 0) && (y2 >= 0) && (x1 < src->x) && (y1 < src->y)) {
01232                 const float B[4] = {0,0,0,0};
01233                 const int ox1 = (x1 < 0), oy1 = (y1 < 0), ox2 = (x2 >= src->x), oy2 = (y2 >= src->y);
01234                 const float* c00 = (ox1 || oy1) ? B : &src->rect[(x1 + y1*src->x)*src->type];
01235                 const float* c10 = (ox2 || oy1) ? B : &src->rect[(x2 + y1*src->x)*src->type];
01236                 const float* c01 = (ox1 || oy2) ? B : &src->rect[(x1 + y2*src->x)*src->type];
01237                 const float* c11 = (ox2 || oy2) ? B : &src->rect[(x2 + y2*src->x)*src->type];
01238                 const float uf = u - ufl, vf = v - vfl;
01239                 const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf;
01240                 col[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0];
01241                 if (src->type != CB_VAL) {
01242                         col[1] = w00*c00[1] + w10*c10[1] + w01*c01[1] + w11*c11[1];
01243                         col[2] = w00*c00[2] + w10*c10[2] + w01*c01[2] + w11*c11[2];
01244                         col[3] = w00*c00[3] + w10*c10[3] + w01*c01[3] + w11*c11[3];
01245                 }
01246         }
01247         else col[0] = col[1] = col[2] = col[3] = 0.f;
01248 }
01249 
01250 // as above, sampling only one channel
01251 void qd_getPixelLerpChan(CompBuf* src, float u, float v, int chan, float* out)
01252 {
01253         const float ufl = floor(u), vfl = floor(v);
01254         const int x1 = (int)ufl, y1 = (int)vfl;
01255         const int x2 = (int)ceil(u), y2 = (int)ceil(v);
01256         if (chan >= src->type) chan = 0;
01257         if ((x2 >= 0) && (y2 >= 0) && (x1 < src->x) && (y1 < src->y)) {
01258                 const float B[4] = {0,0,0,0};
01259                 const int ox1 = (x1 < 0), oy1 = (y1 < 0), ox2 = (x2 >= src->x), oy2 = (y2 >= src->y);
01260                 const float* c00 = (ox1 || oy1) ? B : &src->rect[(x1 + y1*src->x)*src->type + chan];
01261                 const float* c10 = (ox2 || oy1) ? B : &src->rect[(x2 + y1*src->x)*src->type + chan];
01262                 const float* c01 = (ox1 || oy2) ? B : &src->rect[(x1 + y2*src->x)*src->type + chan];
01263                 const float* c11 = (ox2 || oy2) ? B : &src->rect[(x2 + y2*src->x)*src->type + chan];
01264                 const float uf = u - ufl, vf = v - vfl;
01265                 const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf;
01266                 out[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0];
01267         }
01268         else *out = 0.f;
01269 }
01270 
01271 
01272 CompBuf* qd_downScaledCopy(CompBuf* src, int scale)
01273 {
01274         CompBuf* fbuf;
01275         if (scale <= 1)
01276                 fbuf = dupalloc_compbuf(src);
01277         else {
01278                 int nw = src->x/scale, nh = src->y/scale;
01279                 if ((2*(src->x % scale)) > scale) nw++;
01280                 if ((2*(src->y % scale)) > scale) nh++;
01281                 fbuf = alloc_compbuf(nw, nh, src->type, 1);
01282                 {
01283                         int x, y, xx, yy, sx, sy, mx, my;
01284                         float colsum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
01285                         float fscale = 1.f/(float)(scale*scale);
01286                         for (y=0; y<nh; y++) {
01287                                 fRGB* fcolp = (fRGB*)&fbuf->rect[y*fbuf->x*fbuf->type];
01288                                 yy = y*scale;
01289                                 my = yy + scale;
01290                                 if (my > src->y) my = src->y;
01291                                 for (x=0; x<nw; x++) {
01292                                         xx = x*scale;
01293                                         mx = xx + scale;
01294                                         if (mx > src->x) mx = src->x;
01295                                         colsum[0] = colsum[1] = colsum[2] = 0.f;
01296                                         for (sy=yy; sy<my; sy++) {
01297                                                 fRGB* scolp = (fRGB*)&src->rect[sy*src->x*src->type];
01298                                                 for (sx=xx; sx<mx; sx++)
01299                                                         fRGB_add(colsum, scolp[sx]);
01300                                         }
01301                                         fRGB_mult(colsum, fscale);
01302                                         fRGB_copy(fcolp[x], colsum);
01303                                 }
01304                         }
01305                 }
01306         }
01307         return fbuf;
01308 }
01309 
01310 // fast g.blur, per channel
01311 // xy var. bits 1 & 2 ca be used to blur in x or y direction separately
01312 void IIR_gauss(CompBuf* src, float sigma, int chan, int xy)
01313 {
01314         double q, q2, sc, cf[4], tsM[9], tsu[3], tsv[3];
01315         double *X, *Y, *W;
01316         int i, x, y, sz;
01317 
01318         // <0.5 not valid, though can have a possibly useful sort of sharpening effect
01319         if (sigma < 0.5) return;
01320         
01321         if ((xy < 1) || (xy > 3)) xy = 3;
01322         
01323         // XXX The YVV macro defined below explicitely expects sources of at least 3x3 pixels,
01324         //     so just skiping blur along faulty direction if src's def is below that limit!
01325         if (src->x < 3) xy &= ~(int) 1;
01326         if (src->y < 3) xy &= ~(int) 2;
01327         if (xy < 1) return;
01328         
01329         // see "Recursive Gabor Filtering" by Young/VanVliet
01330         // all factors here in double.prec. Required, because for single.prec it seems to blow up if sigma > ~200
01331         if (sigma >= 3.556)
01332                 q = 0.9804*(sigma - 3.556) + 2.5091;
01333         else // sigma >= 0.5
01334                 q = (0.0561*sigma + 0.5784)*sigma - 0.2568;
01335         q2 = q*q;
01336         sc = (1.1668 + q)*(3.203729649  + (2.21566 + q)*q);
01337         // no gabor filtering here, so no complex multiplies, just the regular coefs.
01338         // all negated here, so as not to have to recalc Triggs/Sdika matrix
01339         cf[1] = q*(5.788961737 + (6.76492 + 3.0*q)*q)/ sc;
01340         cf[2] = -q2*(3.38246 + 3.0*q)/sc;
01341         // 0 & 3 unchanged
01342         cf[3] = q2*q/sc;
01343         cf[0] = 1.0 - cf[1] - cf[2] - cf[3];
01344 
01345         // Triggs/Sdika border corrections,
01346         // it seems to work, not entirely sure if it is actually totally correct,
01347         // Besides J.M.Geusebroek's anigauss.c (see http://www.science.uva.nl/~mark),
01348         // found one other implementation by Cristoph Lampert,
01349         // but neither seem to be quite the same, result seems to be ok sofar anyway.
01350         // Extra scale factor here to not have to do it in filter,
01351         // though maybe this had something to with the precision errors
01352         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]));
01353         tsM[0] = sc*(-cf[3]*cf[1] + 1.0 - cf[3]*cf[3] - cf[2]);
01354         tsM[1] = sc*((cf[3] + cf[1])*(cf[2] + cf[3]*cf[1]));
01355         tsM[2] = sc*(cf[3]*(cf[1] + cf[3]*cf[2]));
01356         tsM[3] = sc*(cf[1] + cf[3]*cf[2]);
01357         tsM[4] = sc*(-(cf[2] - 1.0)*(cf[2] + cf[3]*cf[1]));
01358         tsM[5] = sc*(-(cf[3]*cf[1] + cf[3]*cf[3] + cf[2] - 1.0)*cf[3]);
01359         tsM[6] = sc*(cf[3]*cf[1] + cf[2] + cf[1]*cf[1] - cf[2]*cf[2]);
01360         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]);
01361         tsM[8] = sc*(cf[3]*(cf[1] + cf[3]*cf[2]));
01362 
01363 #define YVV(L)\
01364 {\
01365         W[0] = cf[0]*X[0] + cf[1]*X[0] + cf[2]*X[0] + cf[3]*X[0];\
01366         W[1] = cf[0]*X[1] + cf[1]*W[0] + cf[2]*X[0] + cf[3]*X[0];\
01367         W[2] = cf[0]*X[2] + cf[1]*W[1] + cf[2]*W[0] + cf[3]*X[0];\
01368         for (i=3; i<L; i++)\
01369                 W[i] = cf[0]*X[i] + cf[1]*W[i-1] + cf[2]*W[i-2] + cf[3]*W[i-3];\
01370         tsu[0] = W[L-1] - X[L-1];\
01371         tsu[1] = W[L-2] - X[L-1];\
01372         tsu[2] = W[L-3] - X[L-1];\
01373         tsv[0] = tsM[0]*tsu[0] + tsM[1]*tsu[1] + tsM[2]*tsu[2] + X[L-1];\
01374         tsv[1] = tsM[3]*tsu[0] + tsM[4]*tsu[1] + tsM[5]*tsu[2] + X[L-1];\
01375         tsv[2] = tsM[6]*tsu[0] + tsM[7]*tsu[1] + tsM[8]*tsu[2] + X[L-1];\
01376         Y[L-1] = cf[0]*W[L-1] + cf[1]*tsv[0] + cf[2]*tsv[1] + cf[3]*tsv[2];\
01377         Y[L-2] = cf[0]*W[L-2] + cf[1]*Y[L-1] + cf[2]*tsv[0] + cf[3]*tsv[1];\
01378         Y[L-3] = cf[0]*W[L-3] + cf[1]*Y[L-2] + cf[2]*Y[L-1] + cf[3]*tsv[0];\
01379         for (i=L-4; i>=0; i--)\
01380                 Y[i] = cf[0]*W[i] + cf[1]*Y[i+1] + cf[2]*Y[i+2] + cf[3]*Y[i+3];\
01381 }
01382 
01383         // intermediate buffers
01384         sz = MAX2(src->x, src->y);
01385         X = MEM_callocN(sz*sizeof(double), "IIR_gauss X buf");
01386         Y = MEM_callocN(sz*sizeof(double), "IIR_gauss Y buf");
01387         W = MEM_callocN(sz*sizeof(double), "IIR_gauss W buf");
01388         if (xy & 1) {   // H
01389                 for (y=0; y<src->y; ++y) {
01390                         const int yx = y*src->x;
01391                         for (x=0; x<src->x; ++x)
01392                                 X[x] = src->rect[(x + yx)*src->type + chan];
01393                         YVV(src->x);
01394                         for (x=0; x<src->x; ++x)
01395                                 src->rect[(x + yx)*src->type + chan] = Y[x];
01396                 }
01397         }
01398         if (xy & 2) {   // V
01399                 for (x=0; x<src->x; ++x) {
01400                         for (y=0; y<src->y; ++y)
01401                                 X[y] = src->rect[(x + y*src->x)*src->type + chan];
01402                         YVV(src->y);
01403                         for (y=0; y<src->y; ++y)
01404                                 src->rect[(x + y*src->x)*src->type + chan] = Y[y];
01405                 }
01406         }
01407 
01408         MEM_freeN(X);
01409         MEM_freeN(W);
01410         MEM_freeN(Y);
01411 #undef YVV
01412 }
01413