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