d12360e5a7ead984f9436ec12f621018d9bdd6e6
[blender.git] / source / blender / imbuf / intern / filter.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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  * filter.c
28  *
29  * $Id$
30  */
31
32 /** \file blender/imbuf/intern/filter.c
33  *  \ingroup imbuf
34  */
35
36
37 #include "MEM_guardedalloc.h"
38
39 #include "BLI_utildefines.h"
40
41
42
43 #include "IMB_imbuf_types.h"
44 #include "IMB_imbuf.h"
45 #include "IMB_filter.h"
46
47 #include "imbuf.h"
48
49 /************************************************************************/
50 /*                              FILTERS                                 */
51 /************************************************************************/
52
53 static void filtrow(unsigned char *point, int x)
54 {
55         unsigned int c1,c2,c3,error;
56
57         if (x>1){
58                 c1 = c2 = *point;
59                 error = 2;
60                 for(x--;x>0;x--){
61                         c3 = point[4];
62                         c1 += (c2<<1) + c3 + error;
63                         error = c1 & 3;
64                         *point = c1 >> 2;
65                         point += 4;
66                         c1=c2;
67                         c2=c3;
68                 }
69                 *point = (c1 + (c2<<1) + c2 + error) >> 2;
70         }
71 }
72
73 static void filtrowf(float *point, int x)
74 {
75         float c1,c2,c3;
76         
77         if (x>1){
78                 c1 = c2 = *point;
79                 for(x--;x>0;x--){
80                         c3 = point[4];
81                         c1 += (c2 * 2) + c3;
82                         *point = 0.25f*c1;
83                         point += 4;
84                         c1=c2;
85                         c2=c3;
86                 }
87                 *point = 0.25f*(c1 + (c2 * 2) + c2);
88         }
89 }
90
91
92
93 static void filtcolum(unsigned char *point, int y, int skip)
94 {
95         unsigned int c1,c2,c3,error;
96         unsigned char *point2;
97
98         if (y>1){
99                 c1 = c2 = *point;
100                 point2 = point;
101                 error = 2;
102                 for(y--;y>0;y--){
103                         point2 += skip;
104                         c3 = *point2;
105                         c1 += (c2<<1) + c3 +error;
106                         error = c1 & 3;
107                         *point = c1 >> 2;
108                         point=point2;
109                         c1=c2;
110                         c2=c3;
111                 }
112                 *point = (c1 + (c2<<1) + c2 + error) >> 2;
113         }
114 }
115
116 static void filtcolumf(float *point, int y, int skip)
117 {
118         float c1,c2,c3, *point2;
119         
120         if (y>1){
121                 c1 = c2 = *point;
122                 point2 = point;
123                 for(y--;y>0;y--){
124                         point2 += skip;
125                         c3 = *point2;
126                         c1 += (c2 * 2) + c3;
127                         *point = 0.25f*c1;
128                         point=point2;
129                         c1=c2;
130                         c2=c3;
131                 }
132                 *point = 0.25f*(c1 + (c2 * 2) + c2);
133         }
134 }
135
136 void IMB_filtery(struct ImBuf *ibuf)
137 {
138         unsigned char *point;
139         float *pointf;
140         int x, y, skip;
141
142         point = (unsigned char *)ibuf->rect;
143         pointf = ibuf->rect_float;
144
145         x = ibuf->x;
146         y = ibuf->y;
147         skip = x<<2;
148
149         for (;x>0;x--){
150                 if (point) {
151                         if (ibuf->depth > 24) filtcolum(point,y,skip);
152                         point++;
153                         filtcolum(point,y,skip);
154                         point++;
155                         filtcolum(point,y,skip);
156                         point++;
157                         filtcolum(point,y,skip);
158                         point++;
159                 }
160                 if (pointf) {
161                         if (ibuf->depth > 24) filtcolumf(pointf,y,skip);
162                         pointf++;
163                         filtcolumf(pointf,y,skip);
164                         pointf++;
165                         filtcolumf(pointf,y,skip);
166                         pointf++;
167                         filtcolumf(pointf,y,skip);
168                         pointf++;
169                 }
170         }
171 }
172
173
174 void imb_filterx(struct ImBuf *ibuf)
175 {
176         unsigned char *point;
177         float *pointf;
178         int x, y, skip;
179
180         point = (unsigned char *)ibuf->rect;
181         pointf = ibuf->rect_float;
182
183         x = ibuf->x;
184         y = ibuf->y;
185         skip = (x<<2) - 3;
186
187         for (;y>0;y--){
188                 if (point) {
189                         if (ibuf->depth > 24) filtrow(point,x);
190                         point++;
191                         filtrow(point,x);
192                         point++;
193                         filtrow(point,x);
194                         point++;
195                         filtrow(point,x);
196                         point+=skip;
197                 }
198                 if (pointf) {
199                         if (ibuf->depth > 24) filtrowf(pointf,x);
200                         pointf++;
201                         filtrowf(pointf,x);
202                         pointf++;
203                         filtrowf(pointf,x);
204                         pointf++;
205                         filtrowf(pointf,x);
206                         pointf+=skip;
207                 }
208         }
209 }
210
211 void IMB_filterN(ImBuf *out, ImBuf *in)
212 {
213         register char *row1, *row2, *row3;
214         register char *cp, *r11, *r13, *r21, *r23, *r31, *r33;
215         int rowlen, x, y;
216         
217         rowlen= in->x;
218         
219         for(y=0; y<in->y; y++) {
220                 /* setup rows */
221                 row2= (char*)(in->rect + y*rowlen);
222                 row1= (y == 0)? row2: row2 - 4*rowlen;
223                 row3= (y == in->y-1)? row2: row2 + 4*rowlen;
224                 
225                 cp= (char *)(out->rect + y*rowlen);
226                 
227                 for(x=0; x<rowlen; x++) {
228                         if(x == 0) {
229                                 r11 = row1;
230                                 r21 = row1;
231                                 r31 = row1;
232                         }
233                         else {
234                                 r11 = row1-4;
235                                 r21 = row1-4;
236                                 r31 = row1-4;
237                         }
238
239                         if(x == rowlen-1) {
240                                 r13 = row1;
241                                 r23 = row1;
242                                 r33 = row1;
243                         }
244                         else {
245                                 r13 = row1+4;
246                                 r23 = row1+4;
247                                 r33 = row1+4;
248                         }
249
250                         cp[0]= (r11[0] + 2*row1[0] + r13[0] + 2*r21[0] + 4*row2[0] + 2*r23[0] + r31[0] + 2*row3[0] + r33[0])>>4;
251                         cp[1]= (r11[1] + 2*row1[1] + r13[1] + 2*r21[1] + 4*row2[1] + 2*r23[1] + r31[1] + 2*row3[1] + r33[1])>>4;
252                         cp[2]= (r11[2] + 2*row1[2] + r13[2] + 2*r21[2] + 4*row2[2] + 2*r23[2] + r31[2] + 2*row3[2] + r33[2])>>4;
253                         cp[3]= (r11[3] + 2*row1[3] + r13[3] + 2*r21[3] + 4*row2[3] + 2*r23[3] + r31[3] + 2*row3[3] + r33[3])>>4;
254                         cp+=4; row1+=4; row2+=4; row3+=4;
255                 }
256         }
257 }
258
259 void IMB_filter(struct ImBuf *ibuf)
260 {
261         IMB_filtery(ibuf);
262         imb_filterx(ibuf);
263 }
264
265 void IMB_mask_filter_extend(char *mask, int width, int height)
266 {
267         char *row1, *row2, *row3;
268         int rowlen, x, y;
269         char *temprect;
270
271         rowlen= width;
272
273         /* make a copy, to prevent flooding */
274         temprect= MEM_dupallocN(mask);
275
276         for(y=1; y<=height; y++) {
277                 /* setup rows */
278                 row1= (char *)(temprect + (y-2)*rowlen);
279                 row2= row1 + rowlen;
280                 row3= row2 + rowlen;
281                 if(y==1)
282                         row1= row2;
283                 else if(y==height)
284                         row3= row2;
285
286                 for(x=0; x<rowlen; x++) {
287                         if (mask[((y-1)*rowlen)+x]==0) {
288                                 if (*row1 || *row2 || *row3 || *(row1+1) || *(row3+1) ) {
289                                         mask[((y-1)*rowlen)+x] = FILTER_MASK_MARGIN;
290                                 } else if((x!=rowlen-1) && (*(row1+2) || *(row2+2) || *(row3+2)) ) {
291                                         mask[((y-1)*rowlen)+x] = FILTER_MASK_MARGIN;
292                                 }
293                         }
294
295                         if(x!=0) {
296                                 row1++; row2++; row3++;
297                         }
298                 }
299         }
300
301         MEM_freeN(temprect);
302 }
303
304 void IMB_mask_clear(ImBuf *ibuf, char *mask, int val)
305 {
306         int x,y;
307         if (ibuf->rect_float) {
308                 for(x=0; x<ibuf->x; x++) {
309                         for(y=0; y<ibuf->y; y++) {
310                                 if (mask[ibuf->x*y + x] == val) {
311                                         float *col= ibuf->rect_float + 4*(ibuf->x*y + x);
312                                         col[0] = col[1] = col[2] = col[3] = 0.0f;
313                                 }
314                         }
315                 }
316         } else {
317                 /* char buffer */
318                 for(x=0; x<ibuf->x; x++) {
319                         for(y=0; y<ibuf->y; y++) {
320                                 if (mask[ibuf->x*y + x] == val) {
321                                         char *col= (char *)(ibuf->rect + ibuf->x*y + x);
322                                         col[0] = col[1] = col[2] = col[3] = 0;
323                                 }
324                         }
325                 }
326         }
327 }
328
329 #define EXTEND_PIXEL(color, w) if((color)[3]) {r+= w*(color)[0]; g+= w*(color)[1]; b+= w*(color)[2]; a+= w*(color)[3]; tot+=w;}
330
331 /* if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0
332  * 
333  * When a mask is given, only effect pixels with a mask value of 1, defined as BAKE_MASK_MARGIN in rendercore.c
334  * */
335 void IMB_filter_extend(struct ImBuf *ibuf, char *mask)
336 {
337         register char *row1, *row2, *row3;
338         register char *cp; 
339         int rowlen, x, y;
340         
341         rowlen= ibuf->x;
342         
343         
344         if (ibuf->rect_float) {
345                 float *temprect;
346                 float *row1f, *row2f, *row3f;
347                 float *fp;
348                 temprect= MEM_dupallocN(ibuf->rect_float);
349                 
350                 for(y=1; y<=ibuf->y; y++) {
351                         /* setup rows */
352                         row1f= (float *)(temprect + (y-2)*rowlen*4);
353                         row2f= row1f + 4*rowlen;
354                         row3f= row2f + 4*rowlen;
355                         if(y==1)
356                                 row1f= row2f;
357                         else if(y==ibuf->y)
358                                 row3f= row2f;
359                         
360                         fp= (float *)(ibuf->rect_float + (y-1)*rowlen*4);
361                                 
362                         for(x=0; x<rowlen; x++) {
363                                 if((mask==NULL && fp[3]==0.0f) || (mask && mask[((y-1)*rowlen)+x]==1)) {
364                                         int tot= 0;
365                                         float r=0.0f, g=0.0f, b=0.0f, a=0.0f;
366                                         
367                                         EXTEND_PIXEL(row1f, 1);
368                                         EXTEND_PIXEL(row2f, 2);
369                                         EXTEND_PIXEL(row3f, 1);
370                                         EXTEND_PIXEL(row1f+4, 2);
371                                         EXTEND_PIXEL(row3f+4, 2);
372                                         if(x!=rowlen-1) {
373                                                 EXTEND_PIXEL(row1f+8, 1);
374                                                 EXTEND_PIXEL(row2f+8, 2);
375                                                 EXTEND_PIXEL(row3f+8, 1);
376                                         }                                       
377                                         if(tot) {
378                                                 fp[0]= r/tot;
379                                                 fp[1]= g/tot;
380                                                 fp[2]= b/tot;
381                                                 fp[3]= a/tot;
382                                         }
383                                 }
384                                 fp+=4; 
385                                 
386                                 if(x!=0) {
387                                         row1f+=4; row2f+=4; row3f+=4;
388                                 }
389                         }
390                 }
391
392                 MEM_freeN(temprect);
393         }
394         else if(ibuf->rect) {
395                 int *temprect;
396                 
397                 /* make a copy, to prevent flooding */
398                 temprect= MEM_dupallocN(ibuf->rect);
399                 
400                 for(y=1; y<=ibuf->y; y++) {
401                         /* setup rows */
402                         row1= (char *)(temprect + (y-2)*rowlen);
403                         row2= row1 + 4*rowlen;
404                         row3= row2 + 4*rowlen;
405                         if(y==1)
406                                 row1= row2;
407                         else if(y==ibuf->y)
408                                 row3= row2;
409                         
410                         cp= (char *)(ibuf->rect + (y-1)*rowlen);
411                         
412                         for(x=0; x<rowlen; x++) {
413                                 /*if(cp[3]==0) {*/
414                                 if((mask==NULL && cp[3]==0) || (mask && mask[((y-1)*rowlen)+x]==1)) {
415                                         int tot= 0, r=0, g=0, b=0, a=0;
416                                         
417                                         EXTEND_PIXEL(row1, 1);
418                                         EXTEND_PIXEL(row2, 2);
419                                         EXTEND_PIXEL(row3, 1);
420                                         EXTEND_PIXEL(row1+4, 2);
421                                         EXTEND_PIXEL(row3+4, 2);
422                                         if(x!=rowlen-1) {
423                                                 EXTEND_PIXEL(row1+8, 1);
424                                                 EXTEND_PIXEL(row2+8, 2);
425                                                 EXTEND_PIXEL(row3+8, 1);
426                                         }                                       
427                                         if(tot) {
428                                                 cp[0]= r/tot;
429                                                 cp[1]= g/tot;
430                                                 cp[2]= b/tot;
431                                                 cp[3]= a/tot;
432                                         }
433                                 }
434                                 cp+=4;
435                                 
436                                 if(x!=0) {
437                                         row1+=4; row2+=4; row3+=4;
438                                 }
439                         }
440                 }
441                 
442                 MEM_freeN(temprect);
443         }
444 }
445
446 /* threadsafe version, only recreates existing maps */
447 void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
448 {
449         ImBuf *hbuf = ibuf;
450         int curmap = 0;
451         
452         ibuf->miptot= 1;
453         
454         while(curmap < IB_MIPMAP_LEVELS) {
455                 
456                 if(ibuf->mipmap[curmap]) {
457                         
458                         if(use_filter) {
459                                 ImBuf *nbuf= IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect);
460                                 IMB_filterN(nbuf, hbuf);
461                                 imb_onehalf_no_alloc(ibuf->mipmap[curmap], nbuf);
462                                 IMB_freeImBuf(nbuf);
463                         }
464                         else
465                                 imb_onehalf_no_alloc(ibuf->mipmap[curmap], hbuf);
466                 }
467                 
468                 ibuf->miptot= curmap+2;
469                 hbuf= ibuf->mipmap[curmap];
470                 if(hbuf)
471                         hbuf->miplevel= curmap+1;
472                 
473                 if(!hbuf || (hbuf->x <= 2 && hbuf->y <= 2))
474                         break;
475                 
476                 curmap++;
477         }
478 }
479
480 /* frees too (if there) and recreates new data */
481 void IMB_makemipmap(ImBuf *ibuf, int use_filter)
482 {
483         ImBuf *hbuf = ibuf;
484         int curmap = 0;
485
486         imb_freemipmapImBuf(ibuf);
487         
488         ibuf->miptot= 1;
489
490         while(curmap < IB_MIPMAP_LEVELS) {
491                 if(use_filter) {
492                         ImBuf *nbuf= IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect);
493                         IMB_filterN(nbuf, hbuf);
494                         ibuf->mipmap[curmap] = IMB_onehalf(nbuf);
495                         IMB_freeImBuf(nbuf);
496                 }
497                 else
498                         ibuf->mipmap[curmap] = IMB_onehalf(hbuf);
499
500                 ibuf->miptot= curmap+2;
501                 hbuf= ibuf->mipmap[curmap];
502                 hbuf->miplevel= curmap+1;
503
504                 if(!hbuf || (hbuf->x <= 2 && hbuf->y <= 2))
505                         break;
506
507                 curmap++;
508         }
509 }
510
511 ImBuf *IMB_getmipmap(ImBuf *ibuf, int level)
512 {
513         CLAMP(level, 0, ibuf->miptot-1);
514         return (level == 0)? ibuf: ibuf->mipmap[level-1];
515 }
516
517 void IMB_premultiply_rect(unsigned int *rect, int depth, int w, int h)
518 {
519         char *cp;
520         int x, y, val;
521
522         if(depth == 24) {       /* put alpha at 255 */
523                 cp= (char *)(rect);
524
525                 for(y=0; y<h; y++)
526                         for(x=0; x<w; x++, cp+=4)
527                                 cp[3]= 255;
528         }
529         else {
530                 cp= (char *)(rect);
531
532                 for(y=0; y<h; y++) {
533                         for(x=0; x<w; x++, cp+=4) {
534                                 val= cp[3];
535                                 cp[0]= (cp[0]*val)>>8;
536                                 cp[1]= (cp[1]*val)>>8;
537                                 cp[2]= (cp[2]*val)>>8;
538                         }
539                 }
540         }
541 }
542
543 void IMB_premultiply_rect_float(float *rect_float, int depth, int w, int h)
544 {
545         float val, *cp;
546         int x, y;
547
548         if(depth==24) { /* put alpha at 1.0 */
549                 cp= rect_float;
550
551                 for(y=0; y<h; y++)
552                         for(x=0; x<w; x++, cp+=4)
553                                 cp[3]= 1.0;
554         }
555         else {
556                 cp= rect_float;
557                 for(y=0; y<h; y++) {
558                         for(x=0; x<w; x++, cp+=4) {
559                                 val= cp[3];
560                                 cp[0]= cp[0]*val;
561                                 cp[1]= cp[1]*val;
562                                 cp[2]= cp[2]*val;
563                         }
564                 }
565         }
566
567 }
568
569 void IMB_premultiply_alpha(ImBuf *ibuf)
570 {
571         if(ibuf==NULL)
572                 return;
573
574         if(ibuf->rect)
575                 IMB_premultiply_rect(ibuf->rect, ibuf->depth, ibuf->x, ibuf->y);
576
577         if(ibuf->rect_float)
578                 IMB_premultiply_rect_float(ibuf->rect_float, ibuf->depth, ibuf->x, ibuf->y);
579 }
580