doxygen: prevent GPL license block from being parsed as doxygen comment.
[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 "MEM_guardedalloc.h"
33
34 #include "BLI_utildefines.h"
35
36
37
38 #include "IMB_imbuf_types.h"
39 #include "IMB_imbuf.h"
40 #include "IMB_filter.h"
41
42 #include "imbuf.h"
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, *r11, *r13, *r21, *r23, *r31, *r33;
210         int rowlen, x, y;
211         
212         rowlen= in->x;
213         
214         for(y=0; y<in->y; y++) {
215                 /* setup rows */
216                 row2= (char*)(in->rect + y*rowlen);
217                 row1= (y == 0)? row2: row2 - 4*rowlen;
218                 row3= (y == in->y-1)? row2: row2 + 4*rowlen;
219                 
220                 cp= (char *)(out->rect + y*rowlen);
221                 
222                 for(x=0; x<rowlen; x++) {
223                         if(x == 0) {
224                                 r11 = row1;
225                                 r21 = row1;
226                                 r31 = row1;
227                         }
228                         else {
229                                 r11 = row1-4;
230                                 r21 = row1-4;
231                                 r31 = row1-4;
232                         }
233
234                         if(x == rowlen-1) {
235                                 r13 = row1;
236                                 r23 = row1;
237                                 r33 = row1;
238                         }
239                         else {
240                                 r13 = row1+4;
241                                 r23 = row1+4;
242                                 r33 = row1+4;
243                         }
244
245                         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;
246                         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;
247                         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;
248                         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;
249                         cp+=4; row1+=4; row2+=4; row3+=4;
250                 }
251         }
252 }
253
254 void IMB_filter(struct ImBuf *ibuf)
255 {
256         IMB_filtery(ibuf);
257         imb_filterx(ibuf);
258 }
259
260 #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;}
261
262 /* if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0
263  * 
264  * When a mask is given, only effect pixels with a mask value of 1, defined as BAKE_MASK_MARGIN in rendercore.c
265  * */
266 void IMB_filter_extend(struct ImBuf *ibuf, char *mask)
267 {
268         register char *row1, *row2, *row3;
269         register char *cp; 
270         int rowlen, x, y;
271         
272         rowlen= ibuf->x;
273         
274         
275         if (ibuf->rect_float) {
276                 float *temprect;
277                 float *row1f, *row2f, *row3f;
278                 float *fp;
279                 temprect= MEM_dupallocN(ibuf->rect_float);
280                 
281                 for(y=1; y<=ibuf->y; y++) {
282                         /* setup rows */
283                         row1f= (float *)(temprect + (y-2)*rowlen*4);
284                         row2f= row1f + 4*rowlen;
285                         row3f= row2f + 4*rowlen;
286                         if(y==1)
287                                 row1f= row2f;
288                         else if(y==ibuf->y)
289                                 row3f= row2f;
290                         
291                         fp= (float *)(ibuf->rect_float + (y-1)*rowlen*4);
292                                 
293                         for(x=0; x<rowlen; x++) {
294                                 if((mask==NULL && fp[3]==0.0f) || (mask && mask[((y-1)*rowlen)+x]==1)) {
295                                         int tot= 0;
296                                         float r=0.0f, g=0.0f, b=0.0f, a=0.0f;
297                                         
298                                         EXTEND_PIXEL(row1f, 1);
299                                         EXTEND_PIXEL(row2f, 2);
300                                         EXTEND_PIXEL(row3f, 1);
301                                         EXTEND_PIXEL(row1f+4, 2);
302                                         EXTEND_PIXEL(row3f+4, 2);
303                                         if(x!=rowlen-1) {
304                                                 EXTEND_PIXEL(row1f+8, 1);
305                                                 EXTEND_PIXEL(row2f+8, 2);
306                                                 EXTEND_PIXEL(row3f+8, 1);
307                                         }                                       
308                                         if(tot) {
309                                                 fp[0]= r/tot;
310                                                 fp[1]= g/tot;
311                                                 fp[2]= b/tot;
312                                                 fp[3]= a/tot;
313                                         }
314                                 }
315                                 fp+=4; 
316                                 
317                                 if(x!=0) {
318                                         row1f+=4; row2f+=4; row3f+=4;
319                                 }
320                         }
321                 }
322
323                 MEM_freeN(temprect);
324         }
325         else if(ibuf->rect) {
326                 int *temprect;
327                 
328                 /* make a copy, to prevent flooding */
329                 temprect= MEM_dupallocN(ibuf->rect);
330                 
331                 for(y=1; y<=ibuf->y; y++) {
332                         /* setup rows */
333                         row1= (char *)(temprect + (y-2)*rowlen);
334                         row2= row1 + 4*rowlen;
335                         row3= row2 + 4*rowlen;
336                         if(y==1)
337                                 row1= row2;
338                         else if(y==ibuf->y)
339                                 row3= row2;
340                         
341                         cp= (char *)(ibuf->rect + (y-1)*rowlen);
342                         
343                         for(x=0; x<rowlen; x++) {
344                                 /*if(cp[3]==0) {*/
345                                 if((mask==NULL && cp[3]==0) || (mask && mask[((y-1)*rowlen)+x]==1)) {
346                                         int tot= 0, r=0, g=0, b=0, a=0;
347                                         
348                                         EXTEND_PIXEL(row1, 1);
349                                         EXTEND_PIXEL(row2, 2);
350                                         EXTEND_PIXEL(row3, 1);
351                                         EXTEND_PIXEL(row1+4, 2);
352                                         EXTEND_PIXEL(row3+4, 2);
353                                         if(x!=rowlen-1) {
354                                                 EXTEND_PIXEL(row1+8, 1);
355                                                 EXTEND_PIXEL(row2+8, 2);
356                                                 EXTEND_PIXEL(row3+8, 1);
357                                         }                                       
358                                         if(tot) {
359                                                 cp[0]= r/tot;
360                                                 cp[1]= g/tot;
361                                                 cp[2]= b/tot;
362                                                 cp[3]= a/tot;
363                                         }
364                                 }
365                                 cp+=4;
366                                 
367                                 if(x!=0) {
368                                         row1+=4; row2+=4; row3+=4;
369                                 }
370                         }
371                 }
372                 
373                 MEM_freeN(temprect);
374         }
375 }
376
377 /* threadsafe version, only recreates existing maps */
378 void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
379 {
380         ImBuf *hbuf = ibuf;
381         int curmap = 0;
382         
383         ibuf->miptot= 1;
384         
385         while(curmap < IB_MIPMAP_LEVELS) {
386                 
387                 if(ibuf->mipmap[curmap]) {
388                         
389                         if(use_filter) {
390                                 ImBuf *nbuf= IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect);
391                                 IMB_filterN(nbuf, hbuf);
392                                 imb_onehalf_no_alloc(ibuf->mipmap[curmap], nbuf);
393                                 IMB_freeImBuf(nbuf);
394                         }
395                         else
396                                 imb_onehalf_no_alloc(ibuf->mipmap[curmap], hbuf);
397                 }
398                 
399                 ibuf->miptot= curmap+2;
400                 hbuf= ibuf->mipmap[curmap];
401                 if(hbuf)
402                         hbuf->miplevel= curmap+1;
403                 
404                 if(!hbuf || (hbuf->x <= 2 && hbuf->y <= 2))
405                         break;
406                 
407                 curmap++;
408         }
409 }
410
411 /* frees too (if there) and recreates new data */
412 void IMB_makemipmap(ImBuf *ibuf, int use_filter)
413 {
414         ImBuf *hbuf = ibuf;
415         int curmap = 0;
416
417         imb_freemipmapImBuf(ibuf);
418         
419         ibuf->miptot= 1;
420
421         while(curmap < IB_MIPMAP_LEVELS) {
422                 if(use_filter) {
423                         ImBuf *nbuf= IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect);
424                         IMB_filterN(nbuf, hbuf);
425                         ibuf->mipmap[curmap] = IMB_onehalf(nbuf);
426                         IMB_freeImBuf(nbuf);
427                 }
428                 else
429                         ibuf->mipmap[curmap] = IMB_onehalf(hbuf);
430
431                 ibuf->miptot= curmap+2;
432                 hbuf= ibuf->mipmap[curmap];
433                 hbuf->miplevel= curmap+1;
434
435                 if(!hbuf || (hbuf->x == 1 && hbuf->y == 1))
436                         break;
437
438                 curmap++;
439         }
440 }
441
442 ImBuf *IMB_getmipmap(ImBuf *ibuf, int level)
443 {
444         CLAMP(level, 0, ibuf->miptot-1);
445         return (level == 0)? ibuf: ibuf->mipmap[level-1];
446 }
447
448 void IMB_premultiply_rect(unsigned int *rect, int depth, int w, int h)
449 {
450         char *cp;
451         int x, y, val;
452
453         if(depth == 24) {       /* put alpha at 255 */
454                 cp= (char *)(rect);
455
456                 for(y=0; y<h; y++)
457                         for(x=0; x<w; x++, cp+=4)
458                                 cp[3]= 255;
459         }
460         else {
461                 cp= (char *)(rect);
462
463                 for(y=0; y<h; y++) {
464                         for(x=0; x<w; x++, cp+=4) {
465                                 val= cp[3];
466                                 cp[0]= (cp[0]*val)>>8;
467                                 cp[1]= (cp[1]*val)>>8;
468                                 cp[2]= (cp[2]*val)>>8;
469                         }
470                 }
471         }
472 }
473
474 void IMB_premultiply_rect_float(float *rect_float, int depth, int w, int h)
475 {
476         float val, *cp;
477         int x, y;
478
479         if(depth==24) { /* put alpha at 1.0 */
480                 cp= rect_float;
481
482                 for(y=0; y<h; y++)
483                         for(x=0; x<w; x++, cp+=4)
484                                 cp[3]= 1.0;
485         }
486         else {
487                 cp= rect_float;
488                 for(y=0; y<h; y++) {
489                         for(x=0; x<w; x++, cp+=4) {
490                                 val= cp[3];
491                                 cp[0]= cp[0]*val;
492                                 cp[1]= cp[1]*val;
493                                 cp[2]= cp[2]*val;
494                         }
495                 }
496         }
497
498 }
499
500 void IMB_premultiply_alpha(ImBuf *ibuf)
501 {
502         if(ibuf==NULL)
503                 return;
504
505         if(ibuf->rect)
506                 IMB_premultiply_rect(ibuf->rect, ibuf->depth, ibuf->x, ibuf->y);
507
508         if(ibuf->rect_float)
509                 IMB_premultiply_rect_float(ibuf->rect_float, ibuf->depth, ibuf->x, ibuf->y);
510 }
511