Blender V2.61 - r43446

rectop.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) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  * allocimbuf.c
00027  *
00028  */
00029 
00035 #include "BLI_blenlib.h"
00036 #include "BLI_utildefines.h"
00037 
00038 #include "imbuf.h"
00039 #include "IMB_imbuf_types.h"
00040 #include "IMB_imbuf.h"
00041 
00042 #include "IMB_allocimbuf.h"
00043 
00044 
00045 /* blend modes */
00046 
00047 static void blend_color_mix(char *cp, char *cp1, char *cp2, int fac)
00048 {
00049     /* this and other blending modes previously used >>8 instead of /255. both
00050        are not equivalent (>>8 is /256), and the former results in rounding
00051        errors that can turn colors black fast after repeated blending */
00052     int mfac= 255-fac;
00053 
00054     cp[0]= (mfac*cp1[0]+fac*cp2[0])/255;
00055     cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
00056     cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
00057 }
00058 
00059 static void blend_color_add(char *cp, char *cp1, char *cp2, int fac)
00060 {
00061     int temp;
00062 
00063     temp= cp1[0] + ((fac*cp2[0])/255);
00064     if(temp>254) cp[0]= 255; else cp[0]= temp;
00065     temp= cp1[1] + ((fac*cp2[1])/255);
00066     if(temp>254) cp[1]= 255; else cp[1]= temp;
00067     temp= cp1[2] + ((fac*cp2[2])/255);
00068     if(temp>254) cp[2]= 255; else cp[2]= temp;
00069 }
00070 
00071 static void blend_color_sub(char *cp, char *cp1, char *cp2, int fac)
00072 {
00073     int temp;
00074 
00075     temp= cp1[0] - ((fac*cp2[0])/255);
00076     if(temp<0) cp[0]= 0; else cp[0]= temp;
00077     temp= cp1[1] - ((fac*cp2[1])/255);
00078     if(temp<0) cp[1]= 0; else cp[1]= temp;
00079     temp= cp1[2] - ((fac*cp2[2])/255);
00080     if(temp<0) cp[2]= 0; else cp[2]= temp;
00081 }
00082 
00083 static void blend_color_mul(char *cp, char *cp1, char *cp2, int fac)
00084 {
00085     int mfac= 255-fac;
00086     
00087     /* first mul, then blend the fac */
00088     cp[0]= (mfac*cp1[0] + fac*((cp1[0]*cp2[0])/255))/255;
00089     cp[1]= (mfac*cp1[1] + fac*((cp1[1]*cp2[1])/255))/255;
00090     cp[2]= (mfac*cp1[2] + fac*((cp1[2]*cp2[2])/255))/255;
00091 }
00092 
00093 static void blend_color_lighten(char *cp, char *cp1, char *cp2, int fac)
00094 {
00095     /* See if are lighter, if so mix, else dont do anything.
00096     if the paint col is darker then the original, then ignore */
00097     if (cp1[0]+cp1[1]+cp1[2] > cp2[0]+cp2[1]+cp2[2]) {
00098         cp[0]= cp1[0];
00099         cp[1]= cp1[1];
00100         cp[2]= cp1[2];
00101     }
00102     else
00103         blend_color_mix(cp, cp1, cp2, fac);
00104 }
00105 
00106 static void blend_color_darken(char *cp, char *cp1, char *cp2, int fac)
00107 {
00108     /* See if were darker, if so mix, else dont do anything.
00109     if the paint col is brighter then the original, then ignore */
00110     if (cp1[0]+cp1[1]+cp1[2] < cp2[0]+cp2[1]+cp2[2]) {
00111         cp[0]= cp1[0];
00112         cp[1]= cp1[1];
00113         cp[2]= cp1[2];
00114     }
00115     else
00116         blend_color_mix(cp, cp1, cp2, fac);
00117 }
00118 
00119 unsigned int IMB_blend_color(unsigned int src1, unsigned int src2, int fac, IMB_BlendMode mode)
00120 {
00121     unsigned int dst;
00122     int temp;
00123     char *cp, *cp1, *cp2;
00124 
00125     if (fac==0)
00126         return src1;
00127 
00128     cp = (char*)&dst;
00129     cp1 = (char*)&src1;
00130     cp2 = (char*)&src2;
00131 
00132     switch (mode) {
00133         case IMB_BLEND_MIX:
00134             blend_color_mix(cp, cp1, cp2, fac); break;
00135         case IMB_BLEND_ADD:
00136             blend_color_add(cp, cp1, cp2, fac); break;
00137         case IMB_BLEND_SUB:
00138             blend_color_sub(cp, cp1, cp2, fac); break;
00139         case IMB_BLEND_MUL:
00140             blend_color_mul(cp, cp1, cp2, fac); break;
00141         case IMB_BLEND_LIGHTEN:
00142             blend_color_lighten(cp, cp1, cp2, fac); break;
00143         case IMB_BLEND_DARKEN:
00144             blend_color_darken(cp, cp1, cp2, fac); break;
00145         default:
00146             cp[0]= cp1[0];
00147             cp[1]= cp1[1];
00148             cp[2]= cp1[2];
00149     }
00150 
00151     if (mode == IMB_BLEND_ERASE_ALPHA) {
00152         temp= (cp1[3] - fac*cp2[3]/255);
00153         cp[3]= (temp < 0)? 0: temp;
00154     }
00155     else { /* this does ADD_ALPHA also */
00156         temp= (cp1[3] + fac*cp2[3]/255);
00157         cp[3]= (temp > 255)? 255: temp;
00158     }
00159 
00160     return dst;
00161 }
00162 
00163 static void blend_color_mix_float(float *cp, float *cp1, float *cp2, float fac)
00164 {
00165     float mfac= 1.0f-fac;
00166     cp[0]= mfac*cp1[0] + fac*cp2[0];
00167     cp[1]= mfac*cp1[1] + fac*cp2[1];
00168     cp[2]= mfac*cp1[2] + fac*cp2[2];
00169 }
00170 
00171 static void blend_color_add_float(float *cp, float *cp1, float *cp2, float fac)
00172 {
00173     cp[0] = cp1[0] + fac*cp2[0];
00174     cp[1] = cp1[1] + fac*cp2[1];
00175     cp[2] = cp1[2] + fac*cp2[2];
00176 
00177     if (cp[0] > 1.0f) cp[0]= 1.0f;
00178     if (cp[1] > 1.0f) cp[1]= 1.0f;
00179     if (cp[2] > 1.0f) cp[2]= 1.0f;
00180 }
00181 
00182 static void blend_color_sub_float(float *cp, float *cp1, float *cp2, float fac)
00183 {
00184     cp[0] = cp1[0] - fac*cp2[0];
00185     cp[1] = cp1[1] - fac*cp2[1];
00186     cp[2] = cp1[2] - fac*cp2[2];
00187 
00188     if (cp[0] < 0.0f) cp[0]= 0.0f;
00189     if (cp[1] < 0.0f) cp[1]= 0.0f;
00190     if (cp[2] < 0.0f) cp[2]= 0.0f;
00191 }
00192 
00193 static void blend_color_mul_float(float *cp, float *cp1, float *cp2, float fac)
00194 {
00195     float mfac= 1.0f-fac;
00196     
00197     cp[0]= mfac*cp1[0] + fac*(cp1[0]*cp2[0]);
00198     cp[1]= mfac*cp1[1] + fac*(cp1[1]*cp2[1]);
00199     cp[2]= mfac*cp1[2] + fac*(cp1[2]*cp2[2]);
00200 }
00201 
00202 static void blend_color_lighten_float(float *cp, float *cp1, float *cp2, float fac)
00203 {
00204     /* See if are lighter, if so mix, else dont do anything.
00205     if the pafloat col is darker then the original, then ignore */
00206     if (cp1[0]+cp1[1]+cp1[2] > cp2[0]+cp2[1]+cp2[2]) {
00207         cp[0]= cp1[0];
00208         cp[1]= cp1[1];
00209         cp[2]= cp1[2];
00210     }
00211     else
00212         blend_color_mix_float(cp, cp1, cp2, fac);
00213 }
00214 
00215 static void blend_color_darken_float(float *cp, float *cp1, float *cp2, float fac)
00216 {
00217     /* See if were darker, if so mix, else dont do anything.
00218     if the pafloat col is brighter then the original, then ignore */
00219     if (cp1[0]+cp1[1]+cp1[2] < cp2[0]+cp2[1]+cp2[2]) {
00220         cp[0]= cp1[0];
00221         cp[1]= cp1[1];
00222         cp[2]= cp1[2];
00223     }
00224     else
00225         blend_color_mix_float(cp, cp1, cp2, fac);
00226 }
00227 
00228 void IMB_blend_color_float(float *dst, float *src1, float *src2, float fac, IMB_BlendMode mode)
00229 {
00230     if (fac==0) {
00231         dst[0]= src1[0];
00232         dst[1]= src1[1];
00233         dst[2]= src1[2];
00234         dst[3]= src1[3];
00235         return;
00236     }
00237 
00238     switch (mode) {
00239         case IMB_BLEND_MIX:
00240             blend_color_mix_float(dst, src1, src2, fac); break;
00241         case IMB_BLEND_ADD:
00242             blend_color_add_float(dst, src1, src2, fac); break;
00243         case IMB_BLEND_SUB:
00244             blend_color_sub_float(dst, src1, src2, fac); break;
00245         case IMB_BLEND_MUL:
00246             blend_color_mul_float(dst, src1, src2, fac); break;
00247         case IMB_BLEND_LIGHTEN:
00248             blend_color_lighten_float(dst, src1, src2, fac); break;
00249         case IMB_BLEND_DARKEN:
00250             blend_color_darken_float(dst, src1, src2, fac); break;
00251         default:
00252             dst[0]= src1[0];
00253             dst[1]= src1[1];
00254             dst[2]= src1[2];
00255     }
00256 
00257     if (mode == IMB_BLEND_ERASE_ALPHA) {
00258         dst[3]= (src1[3] - fac*src2[3]);
00259         if (dst[3] < 0.0f) dst[3] = 0.0f;
00260     }
00261     else { /* this does ADD_ALPHA also */
00262         dst[3]= (src1[3] + fac*src2[3]);
00263         if (dst[3] > 1.0f) dst[3] = 1.0f;
00264     }
00265 }
00266 
00267 /* clipping */
00268 
00269 void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx, 
00270     int *desty, int *srcx, int *srcy, int *width, int *height)
00271 {
00272     int tmp;
00273 
00274     if (dbuf == NULL) return;
00275     
00276     if (*destx < 0) {
00277         *srcx -= *destx;
00278         *width += *destx;
00279         *destx = 0;
00280     }
00281     if (*srcx < 0) {
00282         *destx -= *srcx;
00283         *width += *srcx;
00284         *srcx = 0;
00285     }
00286     if (*desty < 0) {
00287         *srcy -= *desty;
00288         *height += *desty;
00289         *desty = 0;
00290     }
00291     if (*srcy < 0) {
00292         *desty -= *srcy;
00293         *height += *srcy;
00294         *srcy = 0;
00295     }
00296 
00297     tmp = dbuf->x - *destx;
00298     if (*width > tmp) *width = tmp;
00299     tmp = dbuf->y - *desty;
00300     if (*height > tmp) *height = tmp;
00301 
00302     if (sbuf) {
00303         tmp = sbuf->x - *srcx;
00304         if (*width > tmp) *width = tmp;
00305         tmp = sbuf->y - *srcy;
00306         if (*height > tmp) *height = tmp;
00307     }
00308 
00309     if ((*height <= 0) || (*width <= 0)) {
00310         *width = 0;
00311         *height = 0;
00312     }
00313 }
00314 
00315 /* copy and blend */
00316 
00317 void IMB_rectcpy(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx, 
00318     int desty, int srcx, int srcy, int width, int height)
00319 {
00320     IMB_rectblend(dbuf, sbuf, destx, desty, srcx, srcy, width, height,
00321         IMB_BLEND_COPY);
00322 }
00323 
00324 void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx, 
00325     int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode)
00326 {
00327     unsigned int *drect = NULL, *srect = NULL, *dr, *sr;
00328     float *drectf = NULL, *srectf = NULL, *drf, *srf;
00329     int do_float, do_char, srcskip, destskip, x;
00330 
00331     if (dbuf == NULL) return;
00332 
00333     IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &width, &height);
00334 
00335     if (width == 0 || height == 0) return;
00336     if (sbuf && sbuf->channels!=4) return;
00337     if (dbuf->channels!=4) return;
00338     
00339     do_char = (sbuf && sbuf->rect && dbuf->rect);
00340     do_float = (sbuf && sbuf->rect_float && dbuf->rect_float);
00341 
00342     if (do_char) drect = dbuf->rect + desty * dbuf->x + destx;
00343     if (do_float) drectf = dbuf->rect_float + (desty * dbuf->x + destx)*4;
00344 
00345     destskip = dbuf->x;
00346 
00347     if (sbuf) {
00348         if (do_char) srect = sbuf->rect + srcy * sbuf->x + srcx;
00349         if (do_float) srectf = sbuf->rect_float + (srcy * sbuf->x + srcx)*4;
00350         srcskip = sbuf->x;
00351     } else {
00352         srect = drect;
00353         srectf = drectf;
00354         srcskip = destskip;
00355     }
00356 
00357     if (mode == IMB_BLEND_COPY) {
00358         /* copy */
00359         for (;height > 0; height--) {
00360             if (do_char) {
00361                 memcpy(drect,srect, width * sizeof(int));
00362                 drect += destskip;
00363                 srect += srcskip;
00364             }
00365 
00366             if (do_float) {
00367                 memcpy(drectf,srectf, width * sizeof(float) * 4);
00368                 drectf += destskip*4;
00369                 srectf += srcskip*4;
00370             }
00371         }
00372     }
00373     else if (mode == IMB_BLEND_COPY_RGB) {
00374         /* copy rgb only */
00375         for (;height > 0; height--) {
00376             if (do_char) {
00377                 dr = drect;
00378                 sr = srect;
00379                 for (x=width; x > 0; x--, dr++, sr++) {
00380                     ((char*)dr)[0]= ((char*)sr)[0];
00381                     ((char*)dr)[1]= ((char*)sr)[1];
00382                     ((char*)dr)[2]= ((char*)sr)[2];
00383                 }
00384                 drect += destskip;
00385                 srect += srcskip;
00386             }
00387 
00388             if (do_float) {
00389                 drf = drectf;
00390                 srf = srectf;
00391                 for (x=width; x > 0; x--, drf+=4, srf+=4) {
00392                     drf[0]= srf[0];
00393                     drf[1]= srf[1];
00394                     drf[2]= srf[2];
00395                 }
00396                 drectf += destskip*4;
00397                 srectf += srcskip*4;
00398             }
00399         }
00400     }
00401     else if (mode == IMB_BLEND_COPY_ALPHA) {
00402         /* copy alpha only */
00403         for (;height > 0; height--) {
00404             if (do_char) {
00405                 dr = drect;
00406                 sr = srect;
00407                 for (x=width; x > 0; x--, dr++, sr++)
00408                     ((char*)dr)[3]= ((char*)sr)[3];
00409                 drect += destskip;
00410                 srect += srcskip;
00411             }
00412 
00413             if (do_float) {
00414                 drf = drectf;
00415                 srf = srectf;
00416                 for (x=width; x > 0; x--, drf+=4, srf+=4)
00417                     drf[3]= srf[3];
00418                 drectf += destskip*4;
00419                 srectf += srcskip*4;
00420             }
00421         }
00422     }
00423     else {
00424         /* blend */
00425         for (;height > 0; height--) {
00426             if (do_char) {
00427                 dr = drect;
00428                 sr = srect;
00429                 for (x=width; x > 0; x--, dr++, sr++)
00430                     *dr = IMB_blend_color(*dr, *sr, ((char*)sr)[3], mode);
00431 
00432                 drect += destskip;
00433                 srect += srcskip;
00434             }
00435 
00436             if (do_float) {
00437                 drf = drectf;
00438                 srf = srectf;
00439                 for (x=width; x > 0; x--, drf+=4, srf+=4)
00440                     IMB_blend_color_float(drf, drf, srf, srf[3], mode);
00441 
00442                 drectf += destskip*4;
00443                 srectf += srcskip*4;
00444             }       
00445         }
00446     }
00447 }
00448 
00449 /* fill */
00450 
00451 void IMB_rectfill(struct ImBuf *drect, const float col[4])
00452 {
00453     int num;
00454 
00455     if(drect->rect) {
00456         unsigned int *rrect = drect->rect;
00457         char ccol[4];
00458         
00459         ccol[0]= (int)(col[0]*255);
00460         ccol[1]= (int)(col[1]*255);
00461         ccol[2]= (int)(col[2]*255);
00462         ccol[3]= (int)(col[3]*255);
00463         
00464         num = drect->x * drect->y;
00465         for (;num > 0; num--)
00466             *rrect++ = *((unsigned int*)ccol);
00467     }
00468     
00469     if(drect->rect_float) {
00470         float *rrectf = drect->rect_float;
00471         
00472         num = drect->x * drect->y;
00473         for (;num > 0; num--) {
00474             *rrectf++ = col[0];
00475             *rrectf++ = col[1];
00476             *rrectf++ = col[2];
00477             *rrectf++ = col[3];
00478         }
00479     }   
00480 }
00481 
00482 
00483 void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height, const float col[4], int x1, int y1, int x2, int y2)
00484 {
00485     int i, j;
00486     float a; /* alpha */
00487     float ai; /* alpha inverted */
00488     float aich; /* alpha, inverted, ai/255.0 - Convert char to float at the same time */
00489     if ((!rect && !rectf) || (!col) || col[3]==0.0f)
00490         return;
00491     
00492     /* sanity checks for coords */
00493     CLAMP(x1, 0, width);
00494     CLAMP(x2, 0, width);
00495     CLAMP(y1, 0, height);
00496     CLAMP(y2, 0, height);
00497 
00498     if (x1>x2) SWAP(int,x1,x2);
00499     if (y1>y2) SWAP(int,y1,y2);
00500     if (x1==x2 || y1==y2) return;
00501     
00502     a = col[3];
00503     ai = 1-a;
00504     aich = ai/255.0f;
00505 
00506     if (rect) {
00507         unsigned char *pixel; 
00508         unsigned char chr=0, chg=0, chb=0;
00509         float fr=0, fg=0, fb=0;
00510 
00511         const int alphaint= FTOCHAR(a);
00512         
00513         if (a == 1.0f) {
00514             chr = FTOCHAR(col[0]);
00515             chg = FTOCHAR(col[1]);
00516             chb = FTOCHAR(col[2]);
00517         } else {
00518             fr = col[0]*a;
00519             fg = col[1]*a;
00520             fb = col[2]*a;
00521         }
00522         for (j = 0; j < y2-y1; j++) {
00523             for (i = 0; i < x2-x1; i++) {
00524                 pixel = rect + 4 * (((y1 + j) * width) + (x1 + i));
00525                 if (pixel >= rect && pixel < rect+ (4 * (width * height))) {
00526                     if (a == 1.0f) {
00527                         pixel[0] = chr;
00528                         pixel[1] = chg;
00529                         pixel[2] = chb;
00530                         pixel[3] = 255;
00531                     } else {
00532                         int alphatest;
00533                         pixel[0] = (char)((fr + ((float)pixel[0]*aich))*255.0f);
00534                         pixel[1] = (char)((fg + ((float)pixel[1]*aich))*255.0f);
00535                         pixel[2] = (char)((fb + ((float)pixel[2]*aich))*255.0f);
00536                         pixel[3] = (char)((alphatest= ((int)pixel[3] + alphaint)) < 255 ? alphatest : 255);
00537                     }
00538                 }
00539             }
00540         }
00541     }
00542     
00543     if (rectf) {
00544         float *pixel;
00545         for (j = 0; j < y2-y1; j++) {
00546             for (i = 0; i < x2-x1; i++) {
00547                 pixel = rectf + 4 * (((y1 + j) * width) + (x1 + i));
00548                 if (a == 1.0f) {
00549                     pixel[0] = col[0];
00550                     pixel[1] = col[1];
00551                     pixel[2] = col[2];
00552                     pixel[3] = 1.0f;
00553                 } else {
00554                     float alphatest;
00555                     pixel[0] = (col[0]*a) + (pixel[0]*ai);
00556                     pixel[1] = (col[1]*a) + (pixel[1]*ai);
00557                     pixel[2] = (col[2]*a) + (pixel[2]*ai);
00558                     pixel[3] = (alphatest= (pixel[3] + a)) < 1.0f ? alphatest : 1.0f;
00559                 }
00560             }
00561         }
00562     }
00563 }
00564 
00565 void IMB_rectfill_area(struct ImBuf *ibuf, float *col, int x1, int y1, int x2, int y2)
00566 {
00567     if (!ibuf) return;
00568     buf_rectfill_area((unsigned char *) ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, col, x1, y1, x2, y2);
00569 }
00570 
00571 
00572 void IMB_rectfill_alpha(ImBuf *ibuf, const float value)
00573 {
00574     int i;
00575     if (ibuf->rect_float) {
00576         float *fbuf= ibuf->rect_float + 3;
00577         for (i = ibuf->x * ibuf->y; i > 0; i--, fbuf+= 4) { *fbuf = value; }
00578     }
00579     else {
00580         const unsigned char cvalue= value * 255;
00581         unsigned char *cbuf= ((unsigned char *)ibuf->rect) + 3;
00582         for (i = ibuf->x * ibuf->y; i > 0; i--, cbuf+= 4) { *cbuf = cvalue; }
00583     }
00584 }