591ab066c57f1297aec36e4770574dc57d112f44
[blender-staging.git] / source / blender / imbuf / intern / rectop.c
1 /**
2  *
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30  * allocimbuf.c
31  *
32  * $Id$
33  */
34
35 #include "BLI_blenlib.h"
36
37 #include "imbuf.h"
38 #include "imbuf_patch.h"
39 #include "IMB_imbuf_types.h"
40 #include "IMB_imbuf.h"
41
42 #include "IMB_allocimbuf.h"
43
44 /* blend modes */
45
46 static void blend_color_mix(char *cp, char *cp1, char *cp2, int fac)
47 {
48         /* this and other blending modes previously used >>8 instead of /255. both
49            are not equivalent (>>8 is /256), and the former results in rounding
50            errors that can turn colors black fast after repeated blending */
51         int mfac= 255-fac;
52
53         cp[0]= (mfac*cp1[0]+fac*cp2[0])/255;
54         cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
55         cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
56 }
57
58 static void blend_color_add(char *cp, char *cp1, char *cp2, int fac)
59 {
60         int temp;
61
62         temp= cp1[0] + ((fac*cp2[0])/255);
63         if(temp>254) cp[0]= 255; else cp[0]= temp;
64         temp= cp1[1] + ((fac*cp2[1])/255);
65         if(temp>254) cp[1]= 255; else cp[1]= temp;
66         temp= cp1[2] + ((fac*cp2[2])/255);
67         if(temp>254) cp[2]= 255; else cp[2]= temp;
68 }
69
70 static void blend_color_sub(char *cp, char *cp1, char *cp2, int fac)
71 {
72         int temp;
73
74         temp= cp1[0] - ((fac*cp2[0])/255);
75         if(temp<0) cp[0]= 0; else cp[0]= temp;
76         temp= cp1[1] - ((fac*cp2[1])/255);
77         if(temp<0) cp[1]= 0; else cp[1]= temp;
78         temp= cp1[2] - ((fac*cp2[2])/255);
79         if(temp<0) cp[2]= 0; else cp[2]= temp;
80 }
81
82 static void blend_color_mul(char *cp, char *cp1, char *cp2, int fac)
83 {
84         int mfac= 255-fac;
85         
86         /* first mul, then blend the fac */
87         cp[0]= (mfac*cp1[0] + fac*((cp1[0]*cp2[0])/255))/255;
88         cp[1]= (mfac*cp1[1] + fac*((cp1[1]*cp2[1])/255))/255;
89         cp[2]= (mfac*cp1[2] + fac*((cp1[2]*cp2[2])/255))/255;
90 }
91
92 static void blend_color_lighten(char *cp, char *cp1, char *cp2, int fac)
93 {
94         /* See if are lighter, if so mix, else dont do anything.
95         if the paint col is darker then the original, then ignore */
96         if (cp1[0]+cp1[1]+cp1[2] > cp2[0]+cp2[1]+cp2[2]) {
97                 cp[0]= cp1[0];
98                 cp[1]= cp1[1];
99                 cp[2]= cp1[2];
100         }
101         else
102                 blend_color_mix(cp, cp1, cp2, fac);
103 }
104
105 static void blend_color_darken(char *cp, char *cp1, char *cp2, int fac)
106 {
107         /* See if were darker, if so mix, else dont do anything.
108         if the paint col is brighter then the original, then ignore */
109         if (cp1[0]+cp1[1]+cp1[2] < cp2[0]+cp2[1]+cp2[2]) {
110                 cp[0]= cp1[0];
111                 cp[1]= cp1[1];
112                 cp[2]= cp1[2];
113         }
114         else
115                 blend_color_mix(cp, cp1, cp2, fac);
116 }
117
118 unsigned int IMB_blend_color(unsigned int src1, unsigned int src2, int fac, IMB_BlendMode mode)
119 {
120         unsigned int dst;
121         int temp;
122         char *cp, *cp1, *cp2;
123
124         if (fac==0)
125                 return src1;
126
127         cp = (char*)&dst;
128         cp1 = (char*)&src1;
129         cp2 = (char*)&src2;
130
131         switch (mode) {
132                 case IMB_BLEND_MIX:
133                         blend_color_mix(cp, cp1, cp2, fac); break;
134                 case IMB_BLEND_ADD:
135                         blend_color_add(cp, cp1, cp2, fac); break;
136                 case IMB_BLEND_SUB:
137                         blend_color_sub(cp, cp1, cp2, fac); break;
138                 case IMB_BLEND_MUL:
139                         blend_color_mul(cp, cp1, cp2, fac); break;
140                 case IMB_BLEND_LIGHTEN:
141                         blend_color_lighten(cp, cp1, cp2, fac); break;
142                 case IMB_BLEND_DARKEN:
143                         blend_color_darken(cp, cp1, cp2, fac); break;
144                 default:
145                         cp[0]= cp1[0];
146                         cp[1]= cp1[1];
147                         cp[2]= cp1[2];
148         }
149
150         if (mode == IMB_BLEND_ERASE_ALPHA) {
151                 temp= (cp1[3] - fac*cp2[3]/255);
152                 cp[3]= (temp < 0)? 0: temp;
153         }
154         else { /* this does ADD_ALPHA also */
155                 temp= (cp1[3] + fac*cp2[3]/255);
156                 cp[3]= (temp > 255)? 255: temp;
157         }
158
159         return dst;
160 }
161
162 static void blend_color_mix_float(float *cp, float *cp1, float *cp2, float fac)
163 {
164         float mfac= 1.0-fac;
165         cp[0]= mfac*cp1[0] + fac*cp2[0];
166         cp[1]= mfac*cp1[1] + fac*cp2[1];
167         cp[2]= mfac*cp1[2] + fac*cp2[2];
168 }
169
170 static void blend_color_add_float(float *cp, float *cp1, float *cp2, float fac)
171 {
172         cp[0] = cp1[0] + fac*cp2[0];
173         cp[1] = cp1[1] + fac*cp2[1];
174         cp[2] = cp1[2] + fac*cp2[2];
175
176         if (cp[0] > 1.0f) cp[0]= 1.0f;
177         if (cp[1] > 1.0f) cp[1]= 1.0f;
178         if (cp[2] > 1.0f) cp[2]= 1.0f;
179 }
180
181 static void blend_color_sub_float(float *cp, float *cp1, float *cp2, float fac)
182 {
183         cp[0] = cp1[0] - fac*cp2[0];
184         cp[1] = cp1[1] - fac*cp2[1];
185         cp[2] = cp1[2] - fac*cp2[2];
186
187         if (cp[0] < 0.0f) cp[0]= 0.0f;
188         if (cp[1] < 0.0f) cp[1]= 0.0f;
189         if (cp[2] < 0.0f) cp[2]= 0.0f;
190 }
191
192 static void blend_color_mul_float(float *cp, float *cp1, float *cp2, float fac)
193 {
194         float mfac= 1.0-fac;
195         
196         cp[0]= mfac*cp1[0] + fac*(cp1[0]*cp2[0]);
197         cp[1]= mfac*cp1[1] + fac*(cp1[1]*cp2[1]);
198         cp[2]= mfac*cp1[2] + fac*(cp1[2]*cp2[2]);
199 }
200
201 static void blend_color_lighten_float(float *cp, float *cp1, float *cp2, float fac)
202 {
203         /* See if are lighter, if so mix, else dont do anything.
204         if the pafloat col is darker then the original, then ignore */
205         if (cp1[0]+cp1[1]+cp1[2] > cp2[0]+cp2[1]+cp2[2]) {
206                 cp[0]= cp1[0];
207                 cp[1]= cp1[1];
208                 cp[2]= cp1[2];
209         }
210         else
211                 blend_color_mix_float(cp, cp1, cp2, fac);
212 }
213
214 static void blend_color_darken_float(float *cp, float *cp1, float *cp2, float fac)
215 {
216         /* See if were darker, if so mix, else dont do anything.
217         if the pafloat col is brighter then the original, then ignore */
218         if (cp1[0]+cp1[1]+cp1[2] < cp2[0]+cp2[1]+cp2[2]) {
219                 cp[0]= cp1[0];
220                 cp[1]= cp1[1];
221                 cp[2]= cp1[2];
222         }
223         else
224                 blend_color_mix_float(cp, cp1, cp2, fac);
225 }
226
227 void IMB_blend_color_float(float *dst, float *src1, float *src2, float fac, IMB_BlendMode mode)
228 {
229         if (fac==0) {
230                 dst[0]= src1[0];
231                 dst[1]= src1[1];
232                 dst[2]= src1[2];
233                 dst[3]= src1[3];
234                 return;
235         }
236
237         switch (mode) {
238                 case IMB_BLEND_MIX:
239                         blend_color_mix_float(dst, src1, src2, fac); break;
240                 case IMB_BLEND_ADD:
241                         blend_color_add_float(dst, src1, src2, fac); break;
242                 case IMB_BLEND_SUB:
243                         blend_color_sub_float(dst, src1, src2, fac); break;
244                 case IMB_BLEND_MUL:
245                         blend_color_mul_float(dst, src1, src2, fac); break;
246                 case IMB_BLEND_LIGHTEN:
247                         blend_color_lighten_float(dst, src1, src2, fac); break;
248                 case IMB_BLEND_DARKEN:
249                         blend_color_darken_float(dst, src1, src2, fac); break;
250                 default:
251                         dst[0]= src1[0];
252                         dst[1]= src1[1];
253                         dst[2]= src1[2];
254         }
255
256         if (mode == IMB_BLEND_ERASE_ALPHA) {
257                 dst[3]= (src1[3] - fac*src2[3]);
258                 if (dst[3] < 0.0f) dst[3] = 0.0f;
259         }
260         else { /* this does ADD_ALPHA also */
261                 dst[3]= (src1[3] + fac*src2[3]);
262                 if (dst[3] > 1.0f) dst[3] = 1.0f;
263         }
264 }
265
266 /* clipping */
267
268 void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx, 
269         int *desty, int *srcx, int *srcy, int *width, int *height)
270 {
271         int tmp;
272
273         if (dbuf == NULL) return;
274         
275         if (*destx < 0) {
276                 *srcx -= *destx;
277                 *width += *destx;
278                 *destx = 0;
279         }
280         if (*srcx < 0) {
281                 *destx -= *srcx;
282                 *width += *destx;
283                 *srcx = 0;
284         }
285         if (*desty < 0) {
286                 *srcy -= *desty;
287                 *height += *desty;
288                 *desty = 0;
289         }
290         if (*srcy < 0) {
291                 *desty -= *srcy;
292                 *height += *desty;
293                 *srcy = 0;
294         }
295
296         tmp = dbuf->x - *destx;
297         if (*width > tmp) *width = tmp;
298         tmp = dbuf->y - *desty;
299         if (*height > tmp) *height = tmp;
300
301         if (sbuf) {
302                 tmp = sbuf->x - *srcx;
303                 if (*width > tmp) *width = tmp;
304                 tmp = sbuf->y - *srcy;
305                 if (*height > tmp) *height = tmp;
306         }
307
308         if ((*height <= 0) || (*width <= 0)) {
309                 *width = 0;
310                 *height = 0;
311         }
312 }
313
314 /* copy and blend */
315
316 void IMB_rectcpy(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx, 
317         int desty, int srcx, int srcy, int width, int height)
318 {
319         IMB_rectblend(dbuf, sbuf, destx, desty, srcx, srcy, width, height,
320                 IMB_BLEND_COPY);
321 }
322
323 void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx, 
324         int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode)
325 {
326         unsigned int *drect = NULL, *srect = NULL, *dr, *sr;
327         float *drectf = NULL, *srectf = NULL, *drf, *srf;
328         int do_float, do_char, srcskip, destskip, x;
329
330         if (dbuf == NULL) return;
331
332         IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &width, &height);
333
334         if (width == 0 || height == 0) return;
335         if (sbuf && sbuf->channels!=4) return;
336         if (dbuf->channels!=4) return;
337         
338         do_char = (sbuf && sbuf->rect && dbuf->rect);
339         do_float = (sbuf && sbuf->rect_float && dbuf->rect_float);
340
341         if (do_char) drect = dbuf->rect + desty * dbuf->x + destx;
342         if (do_float) drectf = dbuf->rect_float + (desty * dbuf->x + destx)*4;
343
344         destskip = dbuf->x;
345
346         if (sbuf) {
347                 if (do_char) srect = sbuf->rect + srcy * sbuf->x + srcx;
348                 if (do_float) srectf = sbuf->rect_float + (srcy * sbuf->x + srcx)*4;
349                 srcskip = sbuf->x;
350         } else {
351                 srect = drect;
352                 srectf = drectf;
353                 srcskip = destskip;
354         }
355
356         if (mode == IMB_BLEND_COPY) {
357                 /* copy */
358                 for (;height > 0; height--) {
359                         if (do_char) {
360                                 memcpy(drect,srect, width * sizeof(int));
361                                 drect += destskip;
362                                 srect += srcskip;
363                         }
364
365                         if (do_float) {
366                                 memcpy(drectf,srectf, width * sizeof(float) * 4);
367                                 drectf += destskip*4;
368                                 srectf += srcskip*4;
369                         }
370                 }
371         }
372         else if (mode == IMB_BLEND_COPY_RGB) {
373                 /* copy rgb only */
374                 for (;height > 0; height--) {
375                         if (do_char) {
376                                 dr = drect;
377                                 sr = srect;
378                                 for (x=width; x > 0; x--, dr++, sr++) {
379                                         ((char*)dr)[0]= ((char*)sr)[0];
380                                         ((char*)dr)[1]= ((char*)sr)[1];
381                                         ((char*)dr)[2]= ((char*)sr)[2];
382                                 }
383                                 drect += destskip;
384                                 srect += srcskip;
385                         }
386
387                         if (do_float) {
388                                 drf = drectf;
389                                 srf = srectf;
390                                 for (x=width; x > 0; x--, drf+=4, srf+=4) {
391                                         drf[0]= srf[0];
392                                         drf[1]= srf[1];
393                                         drf[2]= srf[2];
394                                 }
395                                 drectf += destskip*4;
396                                 srectf += srcskip*4;
397                         }
398                 }
399         }
400         else if (mode == IMB_BLEND_COPY_ALPHA) {
401                 /* copy alpha only */
402                 for (;height > 0; height--) {
403                         if (do_char) {
404                                 dr = drect;
405                                 sr = srect;
406                                 for (x=width; x > 0; x--, dr++, sr++)
407                                         ((char*)dr)[3]= ((char*)sr)[3];
408                                 drect += destskip;
409                                 srect += srcskip;
410                         }
411
412                         if (do_float) {
413                                 drf = drectf;
414                                 srf = srectf;
415                                 for (x=width; x > 0; x--, drf+=4, srf+=4)
416                                         drf[3]= srf[3];
417                                 drectf += destskip*4;
418                                 srectf += srcskip*4;
419                         }
420                 }
421         }
422         else {
423                 /* blend */
424                 for (;height > 0; height--) {
425                         if (do_char) {
426                                 dr = drect;
427                                 sr = srect;
428                                 for (x=width; x > 0; x--, dr++, sr++)
429                                         *dr = IMB_blend_color(*dr, *sr, ((char*)sr)[3], mode);
430
431                                 drect += destskip;
432                                 srect += srcskip;
433                         }
434
435                         if (do_float) {
436                                 drf = drectf;
437                                 srf = srectf;
438                                 for (x=width; x > 0; x--, drf+=4, srf+=4)
439                                         IMB_blend_color_float(drf, drf, srf, srf[3], mode);
440
441                                 drectf += destskip*4;
442                                 srectf += srcskip*4;
443                         }               
444                 }
445         }
446 }
447
448 void IMB_rectblend_torus(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx, 
449         int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode)
450 {
451         int origw, origh, w, h;
452
453         if (dbuf->x == 0 || dbuf->y == 0 || sbuf->x == 0 || sbuf->y == 0)
454                 return;
455
456         /* convert destination and source coordinates too be withing image */
457         destx = destx % dbuf->x;
458         if (destx < 0) destx += dbuf->x;
459         desty = desty % dbuf->y;
460         if (desty < 0) desty += dbuf->y;
461         srcx = srcx % sbuf->x;
462         if (srcx < 0) srcx += sbuf->x;
463         srcy = srcy % sbuf->y;
464         if (srcy < 0) srcy += sbuf->y;
465
466         /* clip width of blending area to destination imbuf, to avoid writing the
467            same pixel twice */
468         origw = w = (width > dbuf->x)? dbuf->x: width;
469         origh = h = (height > dbuf->y)? dbuf->y: height;
470
471         /* clip and blend */
472         IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h);
473         IMB_rectblend(dbuf, sbuf, destx, desty, srcx, srcy, w, h, mode);
474
475         /* do 3 other rects if needed */
476         if (w < origw)
477                 IMB_rectblend(dbuf, sbuf, (destx+w)%dbuf->x, desty, (srcx+w)%sbuf->x, srcy,
478                         origw-w, h, mode);
479         if (h < origh)
480                 IMB_rectblend(dbuf, sbuf, destx, (desty+h)%dbuf->y, srcx, (srcy+h)%sbuf->y,
481                         w, origh-h, mode);
482         if ((w < origw) && (h < origh))
483                 IMB_rectblend(dbuf, sbuf, (destx+w)%dbuf->x, (desty+h)%dbuf->y,
484                         (srcx+w)%sbuf->x, (srcy+h)%sbuf->y, origw-w, origh-h, mode);
485 }
486
487 /* fill */
488
489 void IMB_rectfill(struct ImBuf *drect, float col[4])
490 {
491         int num;
492
493         if(drect->rect) {
494                 unsigned int *rrect = drect->rect;
495                 char ccol[4];
496                 
497                 ccol[0]= (int)(col[0]*255);
498                 ccol[1]= (int)(col[1]*255);
499                 ccol[2]= (int)(col[2]*255);
500                 ccol[3]= (int)(col[3]*255);
501                 
502                 num = drect->x * drect->y;
503                 for (;num > 0; num--)
504                         *rrect++ = *((unsigned int*)ccol);
505         }
506         
507         if(drect->rect_float) {
508                 float *rrectf = drect->rect_float;
509                 
510                 num = drect->x * drect->y;
511                 for (;num > 0; num--) {
512                         *rrectf++ = col[0];
513                         *rrectf++ = col[1];
514                         *rrectf++ = col[2];
515                         *rrectf++ = col[3];
516                 }
517         }       
518 }
519
520 /* maybe we should use BKE_utildefines.h */
521 #define FTOCHAR(val) (val<=0.0f ? 0: (val>=1.0f ? 255: (char)(255.99f*val)))
522 #define CLAMP(a, b, c)          if((a)<(b)) (a)=(b); else if((a)>(c)) (a)=(c)
523 #define SWAP(type, a, b)        { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; }
524 void IMB_rectfill_area(struct ImBuf *ibuf, float *col, int x1, int y1, int x2, int y2)
525 {
526         int i, j;
527         float a, ai;
528         if ((!ibuf) || (!col))
529                 return;
530         
531         /* sanity checks for coords */
532         CLAMP(x1, 0, ibuf->x);
533         CLAMP(x2, 0, ibuf->x);
534         CLAMP(y1, 0, ibuf->y);
535         CLAMP(y2, 0, ibuf->y);
536
537         if (x1>x2) SWAP(int,x1,x2);
538         if (y1>y2) SWAP(int,y1,y2);
539         if (x1==x2 || y1==y2) return;
540         
541         a = col[3];
542         ai = 1-a;
543         
544         if (ibuf->rect) {
545                 unsigned char *img, *pixel; 
546                 unsigned char chr, chg, chb;
547         
548                 chr = FTOCHAR(col[0]);
549                 chg = FTOCHAR(col[1]);
550                 chb = FTOCHAR(col[2]);
551                 
552                 img = (unsigned char *) ibuf->rect;
553                 for (j = 0; j < y2-y1; j++) {
554                         for (i = 0; i < x2-x1; i++) {
555                                 pixel = img + 4 * (((y1 + j) * ibuf->x) + (x1 + i));
556                                 if (a == 1.0) {
557                                         pixel[0] = chr;
558                                         pixel[1] = chg;
559                                         pixel[2] = chb;
560                                 } else {
561                                         pixel[0] = (char)((chr*a) + (pixel[0]*ai));
562                                         pixel[1] = (char)((chg*a) + (pixel[1]*ai));
563                                         pixel[2] = (char)((chb*a) + (pixel[2]*ai));
564                                 }
565                                 
566                         }
567                 }
568         }
569         
570         if (ibuf->rect_float) {
571                 float *img, *pixel;
572                 img = ibuf->rect_float;
573                 for (j = 0; j < y2-y1; j++) {
574                         for (i = 0; i < x2-x1; i++) {
575                                 pixel = img + 4 * (((y1 + j) * ibuf->x) + (x1 + i));
576                                 if (a == 1.0) {
577                                         pixel[0] = col[0];
578                                         pixel[1] = col[1];
579                                         pixel[2] = col[2];
580                                 } else {
581                                         pixel[0] = (col[0]*a) + (pixel[0]*ai);
582                                         pixel[1] = (col[1]*a) + (pixel[1]*ai);
583                                         pixel[2] = (col[2]*a) + (pixel[2]*ai);
584                                 }
585                         }
586                 }
587         }
588 }