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