Long waited feature: Render Baking
[blender.git] / source / blender / imbuf / intern / filter.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  * filter.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 #include "IMB_filter.h"
42
43
44 /************************************************************************/
45 /*                              FILTERS                                 */
46 /************************************************************************/
47
48 static void filtrow(unsigned char *point, int x)
49 {
50         unsigned int c1,c2,c3,error;
51
52         if (x>1){
53                 c1 = c2 = *point;
54                 error = 2;
55                 for(x--;x>0;x--){
56                         c3 = point[4];
57                         c1 += (c2<<1) + c3 + error;
58                         error = c1 & 3;
59                         *point = c1 >> 2;
60                         point += 4;
61                         c1=c2;
62                         c2=c3;
63                 }
64                 *point = (c1 + (c2<<1) + c2 + error) >> 2;
65         }
66 }
67
68 static void filtrowf(float *point, int x)
69 {
70         float c1,c2,c3;
71         
72         if (x>1){
73                 c1 = c2 = *point;
74                 for(x--;x>0;x--){
75                         c3 = point[4];
76                         c1 += (c2 * 2) + c3;
77                         *point = 0.25f*c1;
78                         point += 4;
79                         c1=c2;
80                         c2=c3;
81                 }
82                 *point = 0.25f*(c1 + (c2 * 2) + c2);
83         }
84 }
85
86
87
88 static void filtcolum(unsigned char *point, int y, int skip)
89 {
90         unsigned int c1,c2,c3,error;
91         unsigned char *point2;
92
93         if (y>1){
94                 c1 = c2 = *point;
95                 point2 = point;
96                 error = 2;
97                 for(y--;y>0;y--){
98                         point2 += skip;
99                         c3 = *point2;
100                         c1 += (c2<<1) + c3 +error;
101                         error = c1 & 3;
102                         *point = c1 >> 2;
103                         point=point2;
104                         c1=c2;
105                         c2=c3;
106                 }
107                 *point = (c1 + (c2<<1) + c2 + error) >> 2;
108         }
109 }
110
111 static void filtcolumf(float *point, int y, int skip)
112 {
113         float c1,c2,c3, *point2;
114         
115         if (y>1){
116                 c1 = c2 = *point;
117                 point2 = point;
118                 for(y--;y>0;y--){
119                         point2 += skip;
120                         c3 = *point2;
121                         c1 += (c2 * 2) + c3;
122                         *point = 0.25f*c1;
123                         point=point2;
124                         c1=c2;
125                         c2=c3;
126                 }
127                 *point = 0.25f*(c1 + (c2 * 2) + c2);
128         }
129 }
130
131 void IMB_filtery(struct ImBuf *ibuf)
132 {
133         unsigned char *point;
134         float *pointf;
135         int x, y, skip;
136
137         point = (unsigned char *)ibuf->rect;
138         pointf = ibuf->rect_float;
139
140         x = ibuf->x;
141         y = ibuf->y;
142         skip = x<<2;
143
144         for (;x>0;x--){
145                 if (point) {
146                         if (ibuf->depth > 24) filtcolum(point,y,skip);
147                         point++;
148                         filtcolum(point,y,skip);
149                         point++;
150                         filtcolum(point,y,skip);
151                         point++;
152                         filtcolum(point,y,skip);
153                         point++;
154                 }
155                 if (pointf) {
156                         if (ibuf->depth > 24) filtcolumf(pointf,y,skip);
157                         pointf++;
158                         filtcolumf(pointf,y,skip);
159                         pointf++;
160                         filtcolumf(pointf,y,skip);
161                         pointf++;
162                         filtcolumf(pointf,y,skip);
163                         pointf++;
164                 }
165         }
166 }
167
168
169 void imb_filterx(struct ImBuf *ibuf)
170 {
171         unsigned char *point;
172         float *pointf;
173         int x, y, skip;
174
175         point = (unsigned char *)ibuf->rect;
176         pointf = ibuf->rect_float;
177
178         x = ibuf->x;
179         y = ibuf->y;
180         skip = (x<<2) - 3;
181
182         for (;y>0;y--){
183                 if (point) {
184                         if (ibuf->depth > 24) filtrow(point,x);
185                         point++;
186                         filtrow(point,x);
187                         point++;
188                         filtrow(point,x);
189                         point++;
190                         filtrow(point,x);
191                         point+=skip;
192                 }
193                 if (pointf) {
194                         if (ibuf->depth > 24) filtrowf(pointf,x);
195                         pointf++;
196                         filtrowf(pointf,x);
197                         pointf++;
198                         filtrowf(pointf,x);
199                         pointf++;
200                         filtrowf(pointf,x);
201                         pointf+=skip;
202                 }
203         }
204 }
205
206 void IMB_filterN(ImBuf *out, ImBuf *in)
207 {
208         register char *row1, *row2, *row3;
209         register char *cp;
210         int rowlen, x, y;
211         
212         rowlen= in->x;
213         
214         for(y=2; y<in->y; y++) {
215                 /* setup rows */
216                 row1= (char *)(in->rect + (y-2)*rowlen);
217                 row2= row1 + 4*rowlen;
218                 row3= row2 + 4*rowlen;
219                 
220                 cp= (char *)(out->rect + (y-1)*rowlen);
221                 cp[0]= row2[0];
222                 cp[1]= row2[1];
223                 cp[2]= row2[2];
224                 cp[3]= row2[3];
225                 cp+= 4;
226                 
227                 for(x=2; x<rowlen; x++) {
228                         cp[0]= (row1[0] + 2*row1[4] + row1[8] + 2*row2[0] + 4*row2[4] + 2*row2[8] + row3[0] + 2*row3[4] + row3[8])>>4;
229                         cp[1]= (row1[1] + 2*row1[5] + row1[9] + 2*row2[1] + 4*row2[5] + 2*row2[9] + row3[1] + 2*row3[5] + row3[9])>>4;
230                         cp[2]= (row1[2] + 2*row1[6] + row1[10] + 2*row2[2] + 4*row2[6] + 2*row2[10] + row3[2] + 2*row3[6] + row3[10])>>4;
231                         cp[3]= (row1[3] + 2*row1[7] + row1[11] + 2*row2[3] + 4*row2[7] + 2*row2[11] + row3[3] + 2*row3[7] + row3[11])>>4;
232                         cp+=4; row1+=4; row2+=4; row3+=4;
233                 }
234         }
235 }
236
237 void IMB_filter(struct ImBuf *ibuf)
238 {
239         IMB_filtery(ibuf);
240         imb_filterx(ibuf);
241 }
242
243 #define EXTEND_PIXEL(a, w)      if((a)[3]) {r+= w*(a)[0]; g+= w*(a)[1]; b+= w*(a)[2]; tot+=w;}
244
245 /* if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 255 */
246 void IMB_filter_extend(struct ImBuf *ibuf)
247 {
248         register char *row1, *row2, *row3;
249         register char *cp;
250         int rowlen, x, y;
251         
252         rowlen= ibuf->x;
253         
254         if(ibuf->rect) {
255                 int *temprect;
256                 
257                 /* make a copy, to prevent flooding */
258                 temprect= MEM_dupallocN(ibuf->rect);
259                 
260                 for(y=1; y<=ibuf->y; y++) {
261                         /* setup rows */
262                         row1= (char *)(temprect + (y-2)*rowlen);
263                         row2= row1 + 4*rowlen;
264                         row3= row2 + 4*rowlen;
265                         if(y==1)
266                                 row1= row2;
267                         else if(y==ibuf->y)
268                                 row3= row2;
269                         
270                         cp= (char *)(ibuf->rect + (y-1)*rowlen);
271                         
272                         for(x=0; x<rowlen; x++) {
273                                 if(cp[3]==0) {
274                                         int tot= 0, r=0, g=0, b=0;
275                                         
276                                         EXTEND_PIXEL(row1, 1);
277                                         EXTEND_PIXEL(row2, 2);
278                                         EXTEND_PIXEL(row3, 1);
279                                         EXTEND_PIXEL(row1+4, 2);
280                                         EXTEND_PIXEL(row3+4, 2);
281                                         if(x!=rowlen-1) {
282                                                 EXTEND_PIXEL(row1+8, 1);
283                                                 EXTEND_PIXEL(row2+8, 2);
284                                                 EXTEND_PIXEL(row3+8, 1);
285                                         }                                       
286                                         if(tot) {
287                                                 cp[0]= r/tot;
288                                                 cp[1]= g/tot;
289                                                 cp[2]= b/tot;
290                                                 cp[3]= 255;
291                                         }
292                                 }
293                                 cp+=4; 
294                                 
295                                 if(x!=0) {
296                                         row1+=4; row2+=4; row3+=4;
297                                 }
298                         }
299                 }
300                 
301                 MEM_freeN(temprect);
302         }
303 }
304