merge trunk 17122:17213
[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., 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  * filter.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 #include "IMB_filter.h"
39
40
41 /************************************************************************/
42 /*                              FILTERS                                 */
43 /************************************************************************/
44
45 static void filtrow(unsigned char *point, int x)
46 {
47         unsigned int c1,c2,c3,error;
48
49         if (x>1){
50                 c1 = c2 = *point;
51                 error = 2;
52                 for(x--;x>0;x--){
53                         c3 = point[4];
54                         c1 += (c2<<1) + c3 + error;
55                         error = c1 & 3;
56                         *point = c1 >> 2;
57                         point += 4;
58                         c1=c2;
59                         c2=c3;
60                 }
61                 *point = (c1 + (c2<<1) + c2 + error) >> 2;
62         }
63 }
64
65 static void filtrowf(float *point, int x)
66 {
67         float c1,c2,c3;
68         
69         if (x>1){
70                 c1 = c2 = *point;
71                 for(x--;x>0;x--){
72                         c3 = point[4];
73                         c1 += (c2 * 2) + c3;
74                         *point = 0.25f*c1;
75                         point += 4;
76                         c1=c2;
77                         c2=c3;
78                 }
79                 *point = 0.25f*(c1 + (c2 * 2) + c2);
80         }
81 }
82
83
84
85 static void filtcolum(unsigned char *point, int y, int skip)
86 {
87         unsigned int c1,c2,c3,error;
88         unsigned char *point2;
89
90         if (y>1){
91                 c1 = c2 = *point;
92                 point2 = point;
93                 error = 2;
94                 for(y--;y>0;y--){
95                         point2 += skip;
96                         c3 = *point2;
97                         c1 += (c2<<1) + c3 +error;
98                         error = c1 & 3;
99                         *point = c1 >> 2;
100                         point=point2;
101                         c1=c2;
102                         c2=c3;
103                 }
104                 *point = (c1 + (c2<<1) + c2 + error) >> 2;
105         }
106 }
107
108 static void filtcolumf(float *point, int y, int skip)
109 {
110         float c1,c2,c3, *point2;
111         
112         if (y>1){
113                 c1 = c2 = *point;
114                 point2 = point;
115                 for(y--;y>0;y--){
116                         point2 += skip;
117                         c3 = *point2;
118                         c1 += (c2 * 2) + c3;
119                         *point = 0.25f*c1;
120                         point=point2;
121                         c1=c2;
122                         c2=c3;
123                 }
124                 *point = 0.25f*(c1 + (c2 * 2) + c2);
125         }
126 }
127
128 void IMB_filtery(struct ImBuf *ibuf)
129 {
130         unsigned char *point;
131         float *pointf;
132         int x, y, skip;
133
134         point = (unsigned char *)ibuf->rect;
135         pointf = ibuf->rect_float;
136
137         x = ibuf->x;
138         y = ibuf->y;
139         skip = x<<2;
140
141         for (;x>0;x--){
142                 if (point) {
143                         if (ibuf->depth > 24) filtcolum(point,y,skip);
144                         point++;
145                         filtcolum(point,y,skip);
146                         point++;
147                         filtcolum(point,y,skip);
148                         point++;
149                         filtcolum(point,y,skip);
150                         point++;
151                 }
152                 if (pointf) {
153                         if (ibuf->depth > 24) filtcolumf(pointf,y,skip);
154                         pointf++;
155                         filtcolumf(pointf,y,skip);
156                         pointf++;
157                         filtcolumf(pointf,y,skip);
158                         pointf++;
159                         filtcolumf(pointf,y,skip);
160                         pointf++;
161                 }
162         }
163 }
164
165
166 void imb_filterx(struct ImBuf *ibuf)
167 {
168         unsigned char *point;
169         float *pointf;
170         int x, y, skip;
171
172         point = (unsigned char *)ibuf->rect;
173         pointf = ibuf->rect_float;
174
175         x = ibuf->x;
176         y = ibuf->y;
177         skip = (x<<2) - 3;
178
179         for (;y>0;y--){
180                 if (point) {
181                         if (ibuf->depth > 24) filtrow(point,x);
182                         point++;
183                         filtrow(point,x);
184                         point++;
185                         filtrow(point,x);
186                         point++;
187                         filtrow(point,x);
188                         point+=skip;
189                 }
190                 if (pointf) {
191                         if (ibuf->depth > 24) filtrowf(pointf,x);
192                         pointf++;
193                         filtrowf(pointf,x);
194                         pointf++;
195                         filtrowf(pointf,x);
196                         pointf++;
197                         filtrowf(pointf,x);
198                         pointf+=skip;
199                 }
200         }
201 }
202
203 void IMB_filterN(ImBuf *out, ImBuf *in)
204 {
205         register char *row1, *row2, *row3;
206         register char *cp, *r11, *r13, *r21, *r23, *r31, *r33;
207         int rowlen, x, y;
208         
209         rowlen= in->x;
210         
211         for(y=0; y<in->y; y++) {
212                 /* setup rows */
213                 row2= (char*)(in->rect + y*rowlen);
214                 row1= (y == 0)? row2: row2 - 4*rowlen;
215                 row3= (y == in->y-1)? row2: row2 + 4*rowlen;
216                 
217                 cp= (char *)(out->rect + y*rowlen);
218                 
219                 for(x=0; x<rowlen; x++) {
220                         if(x == 0) {
221                                 r11 = row1;
222                                 r21 = row1;
223                                 r31 = row1;
224                         }
225                         else {
226                                 r11 = row1-4;
227                                 r21 = row1-4;
228                                 r31 = row1-4;
229                         }
230
231                         if(x == rowlen-1) {
232                                 r13 = row1;
233                                 r23 = row1;
234                                 r33 = row1;
235                         }
236                         else {
237                                 r13 = row1+4;
238                                 r23 = row1+4;
239                                 r33 = row1+4;
240                         }
241
242                         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;
243                         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;
244                         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;
245                         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;
246                         cp+=4; row1+=4; row2+=4; row3+=4;
247                 }
248         }
249 }
250
251 void IMB_filter(struct ImBuf *ibuf)
252 {
253         IMB_filtery(ibuf);
254         imb_filterx(ibuf);
255 }
256
257 #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;}
258
259 /* if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0
260  * 
261  * When a mask is given, only effect pixels with a mask value of 1, defined as BAKE_MASK_MARGIN in rendercore.c
262  * */
263 void IMB_filter_extend(struct ImBuf *ibuf, char *mask)
264 {
265         register char *row1, *row2, *row3;
266         register char *cp; 
267         int rowlen, x, y;
268         
269         rowlen= ibuf->x;
270         
271         
272         if (ibuf->rect_float) {
273                 float *temprect;
274                 float *row1f, *row2f, *row3f;
275                 float *fp;
276                 temprect= MEM_dupallocN(ibuf->rect_float);
277                 
278                 for(y=1; y<=ibuf->y; y++) {
279                         /* setup rows */
280                         row1f= (float *)(temprect + (y-2)*rowlen*4);
281                         row2f= row1f + 4*rowlen;
282                         row3f= row2f + 4*rowlen;
283                         if(y==1)
284                                 row1f= row2f;
285                         else if(y==ibuf->y)
286                                 row3f= row2f;
287                         
288                         fp= (float *)(ibuf->rect_float + (y-1)*rowlen*4);
289                                 
290                         for(x=0; x<rowlen; x++) {
291                                 if((mask==NULL && fp[3]==0.0f) || (mask && mask[((y-1)*rowlen)+x]==1)) {
292                                         int tot= 0;
293                                         float r=0.0f, g=0.0f, b=0.0f, a=0.0f;
294                                         
295                                         EXTEND_PIXEL(row1f, 1);
296                                         EXTEND_PIXEL(row2f, 2);
297                                         EXTEND_PIXEL(row3f, 1);
298                                         EXTEND_PIXEL(row1f+4, 2);
299                                         EXTEND_PIXEL(row3f+4, 2);
300                                         if(x!=rowlen-1) {
301                                                 EXTEND_PIXEL(row1f+8, 1);
302                                                 EXTEND_PIXEL(row2f+8, 2);
303                                                 EXTEND_PIXEL(row3f+8, 1);
304                                         }                                       
305                                         if(tot) {
306                                                 fp[0]= r/tot;
307                                                 fp[1]= g/tot;
308                                                 fp[2]= b/tot;
309                                                 fp[3]= a/tot;
310                                         }
311                                 }
312                                 fp+=4; 
313                                 
314                                 if(x!=0) {
315                                         row1f+=4; row2f+=4; row3f+=4;
316                                 }
317                         }
318                 }
319
320                 MEM_freeN(temprect);
321         }
322         else if(ibuf->rect) {
323                 int *temprect;
324                 
325                 /* make a copy, to prevent flooding */
326                 temprect= MEM_dupallocN(ibuf->rect);
327                 
328                 for(y=1; y<=ibuf->y; y++) {
329                         /* setup rows */
330                         row1= (char *)(temprect + (y-2)*rowlen);
331                         row2= row1 + 4*rowlen;
332                         row3= row2 + 4*rowlen;
333                         if(y==1)
334                                 row1= row2;
335                         else if(y==ibuf->y)
336                                 row3= row2;
337                         
338                         cp= (char *)(ibuf->rect + (y-1)*rowlen);
339                         
340                         for(x=0; x<rowlen; x++) {
341                                 /*if(cp[3]==0) {*/
342                                 if((mask==NULL && cp[3]==0) || (mask && mask[((y-1)*rowlen)+x]==1)) {
343                                         int tot= 0, r=0, g=0, b=0, a=0;
344                                         
345                                         EXTEND_PIXEL(row1, 1);
346                                         EXTEND_PIXEL(row2, 2);
347                                         EXTEND_PIXEL(row3, 1);
348                                         EXTEND_PIXEL(row1+4, 2);
349                                         EXTEND_PIXEL(row3+4, 2);
350                                         if(x!=rowlen-1) {
351                                                 EXTEND_PIXEL(row1+8, 1);
352                                                 EXTEND_PIXEL(row2+8, 2);
353                                                 EXTEND_PIXEL(row3+8, 1);
354                                         }                                       
355                                         if(tot) {
356                                                 cp[0]= r/tot;
357                                                 cp[1]= g/tot;
358                                                 cp[2]= b/tot;
359                                                 cp[3]= a/tot;
360                                         }
361                                 }
362                                 cp+=4;
363                                 
364                                 if(x!=0) {
365                                         row1+=4; row2+=4; row3+=4;
366                                 }
367                         }
368                 }
369                 
370                 MEM_freeN(temprect);
371         }
372 }
373
374 void IMB_makemipmap(ImBuf *ibuf, int use_filter)
375 {
376         ImBuf *hbuf= ibuf;
377         int minsize, curmap=0;
378         
379         minsize= ibuf->x<ibuf->y?ibuf->x:ibuf->y;
380         
381         while(minsize>10 && curmap<IB_MIPMAP_LEVELS) {
382                 if(use_filter) {
383                         ImBuf *nbuf= IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect, 0);
384                         IMB_filterN(nbuf, hbuf);
385                         ibuf->mipmap[curmap]= IMB_onehalf(nbuf);
386                         IMB_freeImBuf(nbuf);
387                 }
388                 else {
389                         ibuf->mipmap[curmap]= IMB_onehalf(hbuf);
390                 }
391                 hbuf= ibuf->mipmap[curmap];
392                 
393                 curmap++;
394                 minsize= hbuf->x<hbuf->y?hbuf->x:hbuf->y;
395         }
396 }
397
398