3c2c276b6e4091aa61629dd160ff54b243ee5d3c
[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 #include "BKE_utildefines.h"
33 #include "MEM_guardedalloc.h"
34
35 #include "IMB_imbuf_types.h"
36 #include "IMB_imbuf.h"
37 #include "IMB_filter.h"
38
39 #include "imbuf.h"
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 curmap = 0;
378
379         ibuf->miptot= 1;
380
381         while(curmap < IB_MIPMAP_LEVELS) {
382                 if(use_filter) {
383                         ImBuf *nbuf= IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect);
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                 ibuf->miptot= curmap+2;
392                 hbuf= ibuf->mipmap[curmap];
393                 hbuf->miplevel= curmap+1;
394
395                 if(!hbuf || (hbuf->x == 1 && hbuf->y == 1))
396                         break;
397
398                 curmap++;
399         }
400 }
401
402 ImBuf *IMB_getmipmap(ImBuf *ibuf, int level)
403 {
404         CLAMP(level, 0, ibuf->miptot-1);
405         return (level == 0)? ibuf: ibuf->mipmap[level-1];
406 }
407
408 void IMB_premultiply_rect(unsigned int *rect, int depth, int w, int h)
409 {
410         char *cp;
411         int x, y, val;
412
413         if(depth == 24) {       /* put alpha at 255 */
414                 cp= (char *)(rect);
415
416                 for(y=0; y<h; y++)
417                         for(x=0; x<w; x++, cp+=4)
418                                 cp[3]= 255;
419         }
420         else {
421                 cp= (char *)(rect);
422
423                 for(y=0; y<h; y++) {
424                         for(x=0; x<w; x++, cp+=4) {
425                                 val= cp[3];
426                                 cp[0]= (cp[0]*val)>>8;
427                                 cp[1]= (cp[1]*val)>>8;
428                                 cp[2]= (cp[2]*val)>>8;
429                         }
430                 }
431         }
432 }
433
434 void IMB_premultiply_rect_float(float *rect_float, int depth, int w, int h)
435 {
436         float val, *cp;
437         int x, y;
438
439         if(depth==24) { /* put alpha at 1.0 */
440                 cp= rect_float;
441
442                 for(y=0; y<h; y++)
443                         for(x=0; x<w; x++, cp+=4)
444                                 cp[3]= 1.0;
445         }
446         else {
447                 cp= rect_float;
448                 for(y=0; y<h; y++) {
449                         for(x=0; x<w; x++, cp+=4) {
450                                 val= cp[3];
451                                 cp[0]= cp[0]*val;
452                                 cp[1]= cp[1]*val;
453                                 cp[2]= cp[2]*val;
454                         }
455                 }
456         }
457
458 }
459
460 void IMB_premultiply_alpha(ImBuf *ibuf)
461 {
462         if(ibuf==NULL)
463                 return;
464
465         if(ibuf->rect)
466                 IMB_premultiply_rect(ibuf->rect, ibuf->depth, ibuf->x, ibuf->y);
467
468         if(ibuf->rect_float)
469                 IMB_premultiply_rect_float(ibuf->rect_float, ibuf->depth, ibuf->x, ibuf->y);
470 }
471