Use an enumeration type rather than unnamed integers to specify the different types...
[synfig.git] / synfig-core / trunk / src / synfig / blur.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file synfig/blur.cpp
3 **      \brief Blur Implementation File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include <synfig/general.h>
33 #include <synfig/surface.h>
34
35 #include "blur.h"
36
37 #include <stdexcept>
38 #include <ETL/stringf>
39
40 #include <ETL/pen>
41 #include <ETL/gaussian>
42 #include <ETL/boxblur>
43
44 #endif
45
46 /* === U S I N G =========================================================== */
47
48 using namespace std;
49 using namespace etl;
50 using namespace synfig;
51
52 /* === M A C R O S ========================================================= */
53
54 /* === G L O B A L S ======================================================= */
55
56 /* === P R O C E D U R E S ================================================= */
57
58 /* === M E T H O D S ======================================================= */
59 Point Blur::operator ()(const Point &pos) const
60 {
61         Point blurpos(pos);
62
63         switch(type)
64         {
65         case CROSS:
66                 if(rand()%2)
67                 {
68                         if(size[0])
69                                 blurpos[0]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[0];
70                 }
71                 else
72                 {
73                         if(size[1])
74                                 blurpos[1]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[1];
75                 }
76                 break;
77
78         case DISC:
79                 {
80                         Angle theta=Angle::rotations((float)rand()/(float)RAND_MAX);
81                         Vector::value_type mag=(float)rand()/(float)RAND_MAX;
82                         Vector vect((float)Angle::cos(theta).get()*mag,(float)Angle::sin(theta).get()*mag);
83
84                         blurpos[0]+=vect[0]*size[0];
85                         blurpos[1]+=vect[1]*size[1];
86                 }
87                 break;
88
89         case FASTGAUSSIAN:
90         case GAUSSIAN:
91                 // Not quite a true gaussian blur,
92                 // but the results are close enough for me.
93                 if(size[0])
94                 {
95                         blurpos[0]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[0]*3/4;
96                         blurpos[0]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[0]*3/4;
97                 }
98                 if(size[1])
99                 {
100                         blurpos[1]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[1]*3/4;
101                         blurpos[1]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[1]*3/4;
102                 }
103                 break;
104
105         case BOX:
106         default:
107                 if(size[0])
108                         blurpos[0]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[0];
109                 if(size[1])
110                         blurpos[1]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[1];
111                 break;
112         }
113
114         return blurpos;
115 }
116
117 Point Blur::operator ()(synfig::Real x, synfig::Real y) const
118 {
119         return (*this)(Point(x,y));
120 }
121
122 //blur functions to make my life easier
123
124 template <typename T>
125 static inline T zero()
126 {
127         return (T)0;
128 }
129
130 template <>
131 static inline Color zero<Color>()
132 {
133         return Color::alpha();
134 }
135
136 template <typename T,typename AT,class VP>
137 static void GuassianBlur_2x2(etl::surface<T,AT,VP> &surface)
138 {
139         int x,y;
140         T Tmp1,Tmp2,SR0;
141
142         T *SC0=new T[surface.get_w()];
143
144         memcpy(SC0,surface[0],surface.get_w()*sizeof(T));
145
146         for(y=0;y<surface.get_h();y++)
147         {
148                 SR0=surface[y][0];
149                 for(x=0;x<surface.get_w();x++)
150                 {
151                         Tmp1=surface[y][x];
152                         Tmp2=SR0+Tmp1;
153                         SR0=Tmp1;
154                         surface[y][x]=(SC0[x]+Tmp2)/4;
155                         SC0[x]=Tmp2;
156                 }
157         }
158         delete [] SC0;
159 }
160
161 template <typename T,typename AT,class VP>
162 static void GuassianBlur_3x3(etl::surface<T,AT,VP> &surface)
163 {
164         int x,y,u,v,w,h;
165         T Tmp1,Tmp2,SR0,SR1;
166
167         w=surface.get_w();
168         h=surface.get_h();
169
170         T *SC0=new T[w+1];
171         T *SC1=new T[w+1];
172
173         // Setup the row bufers
174         for(x=0;x<w;x++)SC0[x]=surface[0][x]*4;
175 //      memcpy(SC1,surface[0],w*sizeof(T));
176
177         for(y=0;y<=h;y++)
178         {
179                 if(y>=h)
180                         v=h-1;
181                 else
182                         v=y;
183
184                 SR0=SR1=surface[y][0];
185                 for(x=0;x<=w;x++)
186                 {
187                         if(x>=w)
188                                 u=w-1;
189                         else
190                                 u=x;
191
192                         // Row Machine
193                         Tmp1=surface[v][u];
194                         Tmp2=SR0+Tmp1;
195                         SR0=Tmp1;
196                         Tmp1=SR1+Tmp2;
197                         SR1=Tmp2;
198
199                         // Column Machine
200                         Tmp2=SC0[x]+Tmp1;
201                         SC0[x]=Tmp1;
202                         if(y&&x)
203                                 surface[y-1][x-1]=(SC1[x]+Tmp2)/16;
204                         SC1[x]=Tmp2;
205                 }
206         }
207
208         delete [] SC0;
209         delete [] SC1;
210 }
211
212 template <typename T,typename AT,class VP>
213 inline static void GaussianBlur_5x5_(etl::surface<T,AT,VP> &surface,T *SC0,T *SC1,T *SC2,T *SC3)
214 {
215         int x,y,u,v,w,h;
216         T Tmp1,Tmp2,SR0,SR1,SR2,SR3;
217
218         w=surface.get_w();
219         h=surface.get_h();
220
221         // Setup the row bufers
222         for(x=0;x<w;x++)SC0[x+2]=surface[0][x]*24;
223 //      memset(SC0,0,(w+2)*sizeof(T));
224         memset(SC1,0,(w+2)*sizeof(T));
225         memset(SC2,0,(w+2)*sizeof(T));
226         memset(SC3,0,(w+2)*sizeof(T));
227
228         for(y=0;y<h+2;y++)
229         {
230                 if(y>=h)
231                         v=h-1;
232                 else
233                         v=y;
234
235                 SR0=SR1=SR2=SR3=0;
236                 SR0=surface[v][0]*1.5;
237                 for(x=0;x<w+2;x++)
238                 {
239                         if(x>=w)
240                                 u=w-1;
241                         else
242                                 u=x;
243
244                         // Row Machine
245                         Tmp1=surface[v][u];
246                         Tmp2=SR0+Tmp1;
247                         SR0=Tmp1;
248                         Tmp1=SR1+Tmp2;
249                         SR1=Tmp2;
250                         Tmp2=SR2+Tmp1;
251                         SR2=Tmp1;
252                         Tmp1=SR3+Tmp2;
253                         SR3=Tmp2;
254
255                         // Column Machine
256                         Tmp2=SC0[x]+Tmp1;
257                         SC0[x]=Tmp1;
258                         Tmp1=SC1[x]+Tmp2;
259                         SC1[x]=Tmp2;
260                         Tmp2=SC2[x]+Tmp1;
261                         SC2[x]=Tmp1;
262                         if(y>1&&x>1)
263                                 surface[y-2][x-2]=(SC3[x]+Tmp2)/256;
264                         SC3[x]=Tmp2;
265                 }
266         }
267
268 }
269
270 template <typename T,typename AT,class VP>
271 inline static void GaussianBlur_5x5(etl::surface<T,AT,VP> &surface)
272 {
273         int w=surface.get_w();
274
275         T *SC0=new T[w+2];
276         T *SC1=new T[w+2];
277         T *SC2=new T[w+2];
278         T *SC3=new T[w+2];
279
280         GaussianBlur_5x5_(surface,SC0,SC1,SC2,SC3);
281
282         delete [] SC0;
283         delete [] SC1;
284         delete [] SC2;
285         delete [] SC3;
286 }
287
288 template <typename T,typename AT,class VP>
289 static void GuassianBlur_nxn(etl::surface<T,AT,VP> &surface,int n)
290 {
291         int x,y,u,v,w,h;
292         int half_n=n/2,i;
293         T inv_divisor=pow(2.0,(n-1));
294         T Tmp1,Tmp2;
295         inv_divisor=1.0/(inv_divisor*inv_divisor);
296
297         w=surface.get_w();
298         h=surface.get_h();
299
300     T SR[n-1];
301         T *SC[n-1];
302
303         for(i=0;i<n-1;i++)
304         {
305                 SC[i]=new T[w+half_n];
306                 if(!SC[i])
307                 {
308                         throw(runtime_error(strprintf(__FILE__":%d:Malloc failure",__LINE__)));
309                         return;
310                 }
311                 memset(SC[i],0,(w+half_n)*sizeof(T));
312         }
313
314         // Setup the first row
315 //      for(x=0;x<w;x++)SC[0][x+half_n]=surface[0][x]*550.0;//*pow(2.0,(n-1))*(2.0/n);
316
317         for(y=0;y<h+half_n;y++)
318         {
319                 if(y>=h)
320                         v=h-1;
321                 else
322                         v=y;
323
324                 memset(SR,0,(n-1)*sizeof(T));
325
326 //              SR[0]=surface[v][0]*(2.0-1.9/n);
327
328                 for(x=0;x<w+half_n;x++)
329                 {
330                         if(x>=w)
331                                 u=w-1;
332                         else
333                                 u=x;
334
335                         Tmp1=surface[v][u];
336                         // Row Machine
337                         for(i=0;i<half_n;i++)
338                         {
339                                 Tmp2=SR[i*2]+Tmp1;
340                                 SR[i*2]=Tmp1;
341                                 Tmp1=SR[i*2+1]+Tmp2;
342                                 SR[i*2+1]=Tmp2;
343                         }
344
345                         // Column Machine
346                         for(i=0;i<half_n-1;i++)
347                         {
348                                 Tmp2=SC[i*2][x]+Tmp1;
349                                 SC[i*2][x]=Tmp1;
350                                 Tmp1=SC[i*2+1][x]+Tmp2;
351                                 SC[i*2+1][x]=Tmp2;
352                         }
353                         Tmp2=SC[n-3][x]+Tmp1;
354                         SC[n-3][x]=Tmp1;
355                         if(y>=half_n&&x>=half_n)
356                                 surface[y-half_n][x-half_n]=(SC[n-2][x]+Tmp2)*inv_divisor;
357                         SC[n-2][x]=Tmp2;
358                 }
359         }
360
361         for(i=0;i<n-1;i++)
362                 delete [] SC[i];
363 }
364
365 template <typename T,typename AT,class VP>
366 static void GuassianBlur_2x1(etl::surface<T,AT,VP> &surface)
367 {
368         int x,y;
369         AT Tmp1,Tmp2,SR0;
370
371         for(y=0;y<surface.get_h();y++)
372         {
373                 SR0=surface[y][0];
374                 for(x=0;x<surface.get_w();x++)
375                 {
376                         Tmp1=surface[y][x];
377                         Tmp2=SR0+Tmp1;
378                         SR0=Tmp1;
379                         surface[y][x]=(Tmp2)/2;
380                 }
381         }
382 }
383
384 template <typename T,typename AT,class VP>
385 static void GuassianBlur_3x1(etl::surface<T,AT,VP> &surface)
386 {
387         int x,y;
388         AT Tmp1,Tmp2,SR0,SR1;
389
390         for(y=0;y<surface.get_h();y++)
391         {
392                 SR0=SR1=surface[y][0];
393                 for(x=0;x<surface.get_w();x++)
394                 {
395                         // Row Machine
396                         Tmp1=surface[y][x];
397                         Tmp2=SR0+Tmp1;
398                         SR0=Tmp1;
399                         Tmp1=SR1+Tmp2;
400                         SR1=Tmp2;
401
402                         if(x)
403                                 surface[y][x-1]=(Tmp1)/4;
404                 }
405         }
406 }
407
408 template <typename T,typename AT,class VP>
409 static void GuassianBlur_1x2(etl::surface<T,AT,VP> &surface)
410 {
411         int x,y;
412         AT Tmp1,Tmp2,SR0;
413
414         for(x=0;x<surface.get_w();x++)
415         {
416                 SR0 = zero<T>();
417                 for(y=0;y<surface.get_h();y++)
418                 {
419                         Tmp1=surface[y][x];
420                         Tmp2=SR0+Tmp1;
421                         SR0=Tmp1;
422                         surface[y][x]=(Tmp2)/2;
423                 }
424         }
425 }
426
427 template <typename T,typename AT,class VP>
428 static void GuassianBlur_1x3(etl::surface<T,AT,VP> &surface)
429 {
430         int x,y;
431         AT Tmp1,Tmp2,SR0,SR1;
432
433         for(x=0;x<surface.get_w();x++)
434         {
435                 SR0=SR1=surface[0][x];
436                 for(y=0;y<surface.get_h();y++)
437                 {
438                         // Row Machine
439                         Tmp1=surface[y][x];
440                         Tmp2=SR0+Tmp1;
441                         SR0=Tmp1;
442                         Tmp1=SR1+Tmp2;
443                         SR1=Tmp2;
444
445                         if(y)
446                                 surface[y-1][x]=(Tmp1)/4;
447                 }
448         }
449 }
450
451 //THE GOOD ONE!!!!!!!!!
452 bool Blur::operator ()(const Surface &surface,
453                                                 const Vector &resolution,
454                                                 Surface &out) const
455 {
456         int w = surface.get_w(),
457                 h = surface.get_h();
458
459         if(w == 0 || h == 0 || resolution[0] == 0 || resolution[1] == 0) return false;
460
461         const Real      pw = resolution[0]/w,
462                                 ph = resolution[1]/h;
463
464         int     halfsizex = (int) (abs(size[0]*.5/pw) + 1),
465                 halfsizey = (int) (abs(size[1]*.5/ph) + 1);
466
467         int x,y;
468
469         SuperCallback blurcall(cb,0,5000,5000);
470
471         Surface worksurface(w,h);
472
473         //synfig::info("Blur: check surface = %s", surface_valid(surface)?"true":"false");
474
475         // Premultiply the alpha
476         for(y=0;y<h;y++)
477         {
478                 for(x=0;x<w;x++)
479                 {
480                         Color a = surface[y][x];
481                         a.set_r(a.get_r()*a.get_a());
482                         a.set_g(a.get_g()*a.get_a());
483                         a.set_b(a.get_b()*a.get_a());
484                         worksurface[y][x] = a;
485                 }
486         }
487
488         switch(type)
489         {
490         case Blur::DISC:        // D I S C ----------------------------------------------------------
491                 {
492                         int bw = halfsizex;
493                         int bh = halfsizey;
494
495                         if(size[0] && size[1] && w*h>2)
496                         {
497                                 int x2,y2;
498                                 Surface tmp_surface(worksurface);
499
500                                 for(y=0;y<h;y++)
501                                 {
502                                         for(x=0;x<w;x++)
503                                         {
504                                                 //accumulate all the pixels in an ellipse of w,h about the current pixel
505                                                 Color color=Color::alpha();
506                                                 int total=0;
507
508                                                 for(y2=-bh;y2<=bh;y2++)
509                                                 {
510                                                         for(x2=-bw;x2<=bw;x2++)
511                                                         {
512                                                                 //get the floating point distance away from the origin pixel in relative coords
513                                                                 float tmp_x=(float)x2/bw;
514                                                                 float tmp_y=(float)y2/bh;
515                                                                 tmp_x*=tmp_x;
516                                                                 tmp_y*=tmp_y;
517
518                                                                 //ignore if it's outside of the disc
519                                                                 if( tmp_x+tmp_y>1.0)
520                                                                         continue;
521
522                                                                 //cap the pixel indices to inside the surface
523                                                                 int u= x+x2,
524                                                                         v= y+y2;
525
526                                                                 if( u < 0 )                                     u = 0;
527                                                                 if( u >= w ) u = w-1;
528
529                                                                 if( v < 0 )                             v = 0;
530                                                                 if( v >= h ) v = h-1;
531
532                                                                 //accumulate the color, and # of pixels added in
533                                                                 color += tmp_surface[v][u];
534                                                                 total++;
535                                                         }
536                                                 }
537
538                                                 //blend the color with the original color
539                                                 //if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
540                                                         worksurface[y][x]=color/total;
541                                                 //else
542                                                 //      worksurface[y][x]=Color::blend(color/total,tmp_surface[y][x],get_amount(),get_blend_method());
543                                         }
544                                         if(!blurcall.amount_complete(y,h))
545                                         {
546                                                 //if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
547                                                 return false;
548                                         }
549                                 }
550                                 break;
551                         }
552
553                         //if we don't qualify for disc blur just use box blur
554                 }
555
556         case Blur::BOX: // B O X -------------------------------------------------------
557                 {
558                         //horizontal part
559                         //synfig::info("Blur: Starting Box blur (surface valid %d)", (int)surface_valid(worksurface));
560
561                         Surface temp_surface;
562                         temp_surface.set_wh(w,h);
563
564                         if(size[0])
565                         {
566                                 int length = halfsizex;
567                                 length=std::max(1,length);
568
569                                 //synfig::info("Blur: hbox blur work -> temp %d", length);
570                                 etl::hbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface.begin());
571                         }
572                         else temp_surface = worksurface;
573                         //synfig::info("Blur: hbox finished");
574
575                         //vertical part
576                         //Surface temp_surface2;
577                         //temp_surface2.set_wh(w,h);
578
579                         if(size[1])
580                         {
581                                 int length = halfsizey;
582                                 length = std::max(1,length);
583
584                                 //synfig::info("Blur: vbox blur temp -> work %d",length);
585                                 etl::vbox_blur(temp_surface.begin(),temp_surface.end(),length,worksurface.begin());
586                         }
587                         else worksurface = temp_surface;
588                         //synfig::info("Blur: vbox finished");
589
590                         //blend with the original surface
591                         /*int x,y;
592                         for(y=0;y<h;y++)
593                         {
594                                 for(x=0;x<w;x++)
595                                 {
596                                         worksurface[y][x]=temp_surface2[y][x];//Color::blend(temp_surface2[y][x],worksurface[y][x],get_amount(),get_blend_method());
597                                 }
598                         }*/
599                 }
600                 break;
601
602         case Blur::FASTGAUSSIAN:        // F A S T G A U S S I A N ----------------------------------------------
603                 {
604                         //fast gaussian is treated as a 3x3 type of thing, except expanded to work with the length
605
606                         /*      1       2       1
607                                 2       4       2
608                                 1       2       1
609                         */
610
611                         Surface temp_surface;
612                         temp_surface.set_wh(w,h);
613
614                         //Surface temp_surface2;
615                         //temp_surface2.set_wh(w,h);
616
617                         //horizontal part
618                         if(size[0])
619                         {
620                                 Real length=abs((float)w/(resolution[0]))*size[0]*0.5+1;
621                                 length=std::max(1.0,length);
622
623                                 //two box blurs produces: 1 2 1
624                                 etl::hbox_blur(worksurface.begin(),w,h,(int)(length*3/4),temp_surface.begin());
625                                 etl::hbox_blur(temp_surface.begin(),w,h,(int)(length*3/4),worksurface.begin());
626                         }
627                         //else temp_surface2=worksurface;
628
629                         //vertical part
630                         if(size[1])
631                         {
632                                 Real length=abs((float)h/(resolution[1]))*size[1]*0.5+1;
633                                 length=std::max(1.0,length);
634
635                                 //two box blurs produces: 1 2 1 on the horizontal 1 2 1
636                                 etl::vbox_blur(worksurface.begin(),w,h,(int)(length*3/4),temp_surface.begin());
637                                 etl::vbox_blur(temp_surface.begin(),w,h,(int)(length*3/4),worksurface.begin());
638                         }
639                         //else temp_surface2=temp_surface2;
640
641                         /*int x,y;
642                         for(y=0;y<h;y++)
643                         {
644                                 for(x=0;x<w;x++)
645                                 {
646                                         worksurface[y][x]=temp_surface2[y][x];//Color::blend(temp_surface2[y][x],worksurface[y][x],get_amount(),get_blend_method());
647                                 }
648                         }*/
649                 }
650                 break;
651
652         case Blur::CROSS: // C R O S S  -------------------------------------------------------
653                 {
654                         //horizontal part
655                         Surface temp_surface;
656                         temp_surface.set_wh(worksurface.get_w(),worksurface.get_h());
657
658                         if(size[0])
659                         {
660                                 int length = halfsizex;
661                                 length = std::max(1,length);
662
663                                 etl::hbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface.begin());
664                         }
665                         else temp_surface = worksurface;
666
667                         //vertical part
668                         Surface temp_surface2;
669                         temp_surface2.set_wh(worksurface.get_w(),worksurface.get_h());
670
671                         if(size[1])
672                         {
673                                 int length = halfsizey;
674                                 length = std::max(1,length);
675
676                                 etl::vbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface2.begin());
677                         }
678                         else temp_surface2 = worksurface;
679
680                         //blend the two together
681                         int x,y;
682
683                         for(y=0;y<h;y++)
684                         {
685                                 for(x=0;x<w;x++)
686                                 {
687                                         worksurface[y][x] = (temp_surface[y][x]+temp_surface2[y][x])/2;//Color::blend((temp_surface[y][x]+temp_surface2[y][x])/2,worksurface[y][x],get_amount(),get_blend_method());
688                                 }
689                         }
690
691                         break;
692                 }
693
694         case Blur::GAUSSIAN:    // G A U S S I A N ----------------------------------------------
695                 {
696                         #ifndef GAUSSIAN_ADJUSTMENT
697                         #define GAUSSIAN_ADJUSTMENT             (0.05)
698                         #endif
699
700                         Real    pw = (Real)w/(resolution[0]);
701                         Real    ph = (Real)h/(resolution[1]);
702
703                         Surface temp_surface;
704                         Surface *gauss_surface;
705
706                         //synfig::warning("Didn't crash yet b1");
707
708                         //if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
709                                 gauss_surface = &worksurface;
710                         /*else
711                         {
712                                 temp_surface = worksurface;
713                                 gauss_surface = &temp_surface;
714                         }*/
715
716             /* Squaring the pw and ph values
717                            is necessary to insure consistant
718                            results when rendered to different
719                            resolutions.
720                            Unfortunately, this automatically
721                            squares our rendertime.
722                            There has got to be a faster way...
723                         */
724                         pw=pw*pw;
725                         ph=ph*ph;
726
727                         int bw = (int)(abs(pw)*size[0]*GAUSSIAN_ADJUSTMENT+0.5);
728                         int bh = (int)(abs(ph)*size[1]*GAUSSIAN_ADJUSTMENT+0.5);
729                         int max=bw+bh;
730
731                         Color *SC0=new class Color[w+2];
732                         Color *SC1=new class Color[w+2];
733                         Color *SC2=new class Color[w+2];
734                         Color *SC3=new class Color[w+2];
735                         memset(SC0,0,(w+2)*sizeof(Color));
736                         memset(SC0,0,(w+2)*sizeof(Color));
737                         memset(SC0,0,(w+2)*sizeof(Color));
738                         memset(SC0,0,(w+2)*sizeof(Color));
739
740                         //synfig::warning("Didn't crash yet b2");
741                         //int i = 0;
742
743                         while(bw&&bh)
744                         {
745                                 if(!blurcall.amount_complete(max-(bw+bh),max))return false;
746
747                                 if(bw>=4 && bh>=4)
748                                 {
749                                         etl::gaussian_blur_5x5_(gauss_surface->begin(),gauss_surface->get_w(),gauss_surface->get_h(),SC0,SC1,SC2,SC3);
750                                         bw-=4,bh-=4;
751                                 }
752                                 else
753                                 if(bw>=2 && bh>=2)
754                                 {
755                                         etl::gaussian_blur_3x3(gauss_surface->begin(),gauss_surface->end());
756                                         bw-=2,bh-=2;
757                                 }
758                                 else
759                                 if(bw>=1 && bh>=1)
760                                 {
761                                         GuassianBlur_2x2(*gauss_surface);
762                                         bw--,bh--;
763                                 }
764
765                                 //synfig::warning("Didn't crash yet bi - %d",i++);
766                         }
767                         while(bw)
768                         {
769                                 if(!blurcall.amount_complete(max-(bw+bh),max))return false;
770                                 if(bw>=2)
771                                 {
772                                         GuassianBlur_3x1(*gauss_surface);
773                                         bw-=2;
774                                 }
775                                 else
776                                 if(bw>=1)
777                                 {
778                                         GuassianBlur_2x1(*gauss_surface);
779                                         bw--;
780                                 }
781                                 //synfig::warning("Didn't crash yet bi - %d",i++);
782                         }
783                         while(bh)
784                         {
785                                 if(!blurcall.amount_complete(max-(bw+bh),max))return false;
786                                 if(bh>=2)
787                                 {
788                                         GuassianBlur_1x3(*gauss_surface);
789                                         bh-=2;
790                                 }
791                                 else
792                                 if(bh>=1)
793                                 {
794                                         GuassianBlur_1x2(*gauss_surface);
795                                         bh--;
796                                 }
797                                 //synfig::warning("Didn't crash yet bi - %d",i++);
798                         }
799
800                         delete [] SC0;
801                         delete [] SC1;
802                         delete [] SC2;
803                         delete [] SC3;
804
805                         /*if(get_amount()!=1.0 || get_blend_method()!=Color::BLEND_STRAIGHT)
806                         {
807                                 int x,y;
808                                 for(y=0;y<renddesc.get_h();y++)
809                                         for(x=0;x<renddesc.get_w();x++)
810                                                 worksurface[y][x]=Color::blend(temp_surface[y][x],worksurface[y][x],get_amount(),get_blend_method());
811                         }*/
812                         //synfig::warning("Didn't crash yet b end",i++);
813                 }
814                 break;
815
816                 default:
817                 break;
818         }
819
820         // Scale up the alpha
821
822         //be sure the surface is of the correct size
823         //surface->set_wh(renddesc.get_w(),renddesc.get_h());
824         out.set_wh(w,h);
825
826         //divide out the alpha
827         for(y=0;y<h;y++)
828         {
829                 for(x=0;x<w;x++)
830                 {
831                         Color a = worksurface[y][x];
832                         if(a.get_a())
833                         {
834                                 a.set_r(a.get_r()/a.get_a());
835                                 a.set_g(a.get_g()/a.get_a());
836                                 a.set_b(a.get_b()/a.get_a());
837                                 out[y][x]=a;
838                         }
839                         else out[y][x]=Color::alpha();
840                 }
841         }
842
843         //we are FRIGGGIN done....
844         blurcall.amount_complete(100,100);
845
846         return true;
847 }
848
849 bool Blur::operator ()(const surface<float> &surface,
850                                                 const Vector &resolution,
851                                                 surface<float> &out) const
852 {
853         int w = surface.get_w(),
854                 h = surface.get_h();
855
856         if(w == 0 || h == 0 || resolution[0] == 0 || resolution[1] == 0) return false;
857
858         const Real      pw = resolution[0]/w,
859                                 ph = resolution[1]/h;
860
861         int     halfsizex = (int) (abs(size[0]*.5/pw) + 1),
862                 halfsizey = (int) (abs(size[1]*.5/ph) + 1);
863         int x,y;
864
865         SuperCallback blurcall(cb,0,5000,5000);
866
867         etl::surface<float> worksurface(surface);
868
869         //don't need to premultiply because we are dealing with ONLY alpha
870
871         switch(type)
872         {
873         case Blur::DISC:        // D I S C ----------------------------------------------------------
874                 {
875                         int bw = halfsizex;
876                         int bh = halfsizey;
877
878                         if(size[0] && size[1] && w*h>2)
879                         {
880                                 int x2,y2;
881                                 etl::surface<float> tmp_surface(worksurface);
882
883                                 for(y=0;y<h;y++)
884                                 {
885                                         for(x=0;x<w;x++)
886                                         {
887                                                 //accumulate all the pixels in an ellipse of w,h about the current pixel
888                                                 float a = 0;
889                                                 int total=0;
890
891                                                 for(y2=-bh;y2<=bh;y2++)
892                                                 {
893                                                         for(x2=-bw;x2<=bw;x2++)
894                                                         {
895                                                                 //get the floating point distance away from the origin pixel in relative coords
896                                                                 float tmp_x=(float)x2/bw;
897                                                                 float tmp_y=(float)y2/bh;
898                                                                 tmp_x*=tmp_x;
899                                                                 tmp_y*=tmp_y;
900
901                                                                 //ignore if it's outside of the disc
902                                                                 if( tmp_x+tmp_y>1.0)
903                                                                         continue;
904
905                                                                 //cap the pixel indices to inside the surface
906                                                                 int u= x+x2,
907                                                                         v= y+y2;
908
909                                                                 if( u < 0 )                                     u = 0;
910                                                                 if( u >= w ) u = w-1;
911
912                                                                 if( v < 0 )                             v = 0;
913                                                                 if( v >= h ) v = h-1;
914
915                                                                 //accumulate the color, and # of pixels added in
916                                                                 a += tmp_surface[v][u];
917                                                                 total++;
918                                                         }
919                                                 }
920
921                                                 //blend the color with the original color
922                                                 //if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
923                                                         worksurface[y][x]=a/total;
924                                                 //else
925                                                 //      worksurface[y][x]=Color::blend(color/total,tmp_surface[y][x],get_amount(),get_blend_method());
926                                         }
927                                         if(!blurcall.amount_complete(y,h))
928                                         {
929                                                 //if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
930                                                 return false;
931                                         }
932                                 }
933                                 break;
934                         }
935
936                         //if we don't qualify for disc blur just use box blur
937                 }
938
939         case Blur::BOX: // B O X -------------------------------------------------------
940                 {
941                         //horizontal part
942                         etl::surface<float> temp_surface;
943                         temp_surface.set_wh(w,h);
944
945                         if(size[0])
946                         {
947                                 int length = halfsizex;
948                                 length=std::max(1,length);
949
950                                 etl::hbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface.begin());
951                         }
952                         else temp_surface = worksurface;
953
954                         //vertical part
955                         //etl::surface<float> temp_surface2;
956                         //temp_surface2.set_wh(w,h);
957
958                         if(size[1])
959                         {
960                                 int length = halfsizey;
961                                 length = std::max(1,length);
962                                 etl::vbox_blur(temp_surface.begin(),temp_surface.end(),length,worksurface.begin());
963                         }
964                         else worksurface = temp_surface;
965
966                         //blend with the original surface
967                         /*int x,y;
968                         for(y=0;y<h;y++)
969                         {
970                                 for(x=0;x<w;x++)
971                                 {
972                                         worksurface[y][x]=temp_surface2[y][x];//Color::blend(temp_surface2[y][x],worksurface[y][x],get_amount(),get_blend_method());
973                                 }
974                         }*/
975                 }
976                 break;
977
978         case Blur::FASTGAUSSIAN:        // F A S T G A U S S I A N ----------------------------------------------
979                 {
980                         //fast gaussian is treated as a 3x3 type of thing, except expanded to work with the length
981
982                         /*      1       2       1
983                                 2       4       2
984                                 1       2       1
985                         */
986
987                         etl::surface<float> temp_surface;
988                         temp_surface.set_wh(w,h);
989
990                         //etl::surface<float> temp_surface2;
991                         //temp_surface2.set_wh(w,h);
992
993                         //horizontal part
994                         if(size[0])
995                         {
996                                 Real length=abs((float)w/(resolution[0]))*size[0]*0.5+1;
997                                 length=std::max(1.0,length);
998
999                                 //two box blurs produces: 1 2 1
1000                                 etl::hbox_blur(worksurface.begin(),w,h,(int)(length*3/4),temp_surface.begin());
1001                                 etl::hbox_blur(temp_surface.begin(),w,h,(int)(length*3/4),worksurface.begin());
1002                         }
1003                         //else temp_surface2=worksurface;
1004
1005                         //vertical part
1006                         if(size[1])
1007                         {
1008                                 Real length=abs((float)h/(resolution[1]))*size[1]*0.5+1;
1009                                 length=std::max(1.0,length);
1010
1011                                 //two box blurs produces: 1 2 1 on the horizontal 1 2 1
1012                                 etl::vbox_blur(worksurface.begin(),w,h,(int)(length*3/4),temp_surface.begin());
1013                                 etl::vbox_blur(temp_surface.begin(),w,h,(int)(length*3/4),worksurface.begin());
1014                         }
1015                         //else temp_surface2=temp_surface2;
1016
1017                         /*int x,y;
1018                         for(y=0;y<h;y++)
1019                         {
1020                                 for(x=0;x<w;x++)
1021                                 {
1022                                         worksurface[y][x]=temp_surface2[y][x];//Color::blend(temp_surface2[y][x],worksurface[y][x],get_amount(),get_blend_method());
1023                                 }
1024                         }*/
1025                 }
1026                 break;
1027
1028         case Blur::CROSS: // C R O S S  -------------------------------------------------------
1029                 {
1030                         //horizontal part
1031                         etl::surface<float> temp_surface;
1032                         temp_surface.set_wh(worksurface.get_w(),worksurface.get_h());
1033
1034                         if(size[0])
1035                         {
1036                                 int length = halfsizex;
1037                                 length = std::max(1,length);
1038
1039                                 etl::hbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface.begin());
1040                         }
1041                         else temp_surface = worksurface;
1042
1043                         //vertical part
1044                         etl::surface<float> temp_surface2;
1045                         temp_surface2.set_wh(worksurface.get_w(),worksurface.get_h());
1046
1047                         if(size[1])
1048                         {
1049                                 int length = halfsizey;
1050                                 length = std::max(1,length);
1051
1052                                 etl::vbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface2.begin());
1053                         }
1054                         else temp_surface2 = worksurface;
1055
1056                         //blend the two together
1057                         int x,y;
1058
1059                         for(y=0;y<h;y++)
1060                         {
1061                                 for(x=0;x<w;x++)
1062                                 {
1063                                         worksurface[y][x] = (temp_surface[y][x]+temp_surface2[y][x])/2;//Color::blend((temp_surface[y][x]+temp_surface2[y][x])/2,worksurface[y][x],get_amount(),get_blend_method());
1064                                 }
1065                         }
1066
1067                         break;
1068                 }
1069
1070         case Blur::GAUSSIAN:    // G A U S S I A N ----------------------------------------------
1071                 {
1072                         #ifndef GAUSSIAN_ADJUSTMENT
1073                         #define GAUSSIAN_ADJUSTMENT             (0.05)
1074                         #endif
1075
1076                         Real    pw = (Real)w/(resolution[0]);
1077                         Real    ph = (Real)h/(resolution[1]);
1078
1079                         //etl::surface<float> temp_surface;
1080                         etl::surface<float> *gauss_surface;
1081
1082                         //if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
1083                                 gauss_surface = &worksurface;
1084                         /*else
1085                         {
1086                                 temp_surface = worksurface;
1087                                 gauss_surface = &temp_surface;
1088                         }*/
1089
1090             /* Squaring the pw and ph values
1091                            is necessary to insure consistant
1092                            results when rendered to different
1093                            resolutions.
1094                            Unfortunately, this automatically
1095                            squares our rendertime.
1096                            There has got to be a faster way...
1097                         */
1098                         pw=pw*pw;
1099                         ph=ph*ph;
1100
1101                         int bw = (int)(abs(pw)*size[0]*GAUSSIAN_ADJUSTMENT+0.5);
1102                         int bh = (int)(abs(ph)*size[1]*GAUSSIAN_ADJUSTMENT+0.5);
1103                         int max=bw+bh;
1104
1105                         float *SC0=new float[w+2];
1106                         float *SC1=new float[w+2];
1107                         float *SC2=new float[w+2];
1108                         float *SC3=new float[w+2];
1109
1110                         memset(SC0,0,(w+2)*sizeof(float));
1111                         memset(SC0,0,(w+2)*sizeof(float));
1112                         memset(SC0,0,(w+2)*sizeof(float));
1113                         memset(SC0,0,(w+2)*sizeof(float));
1114
1115                         //int i = 0;
1116
1117                         while(bw&&bh)
1118                         {
1119                                 if(!blurcall.amount_complete(max-(bw+bh),max))return false;
1120
1121                                 if(bw>=4 && bh>=4)
1122                                 {
1123                                         etl::gaussian_blur_5x5_(gauss_surface->begin(),gauss_surface->get_w(),gauss_surface->get_h(),SC0,SC1,SC2,SC3);
1124                                         bw-=4,bh-=4;
1125                                 }
1126                                 else
1127                                 if(bw>=2 && bh>=2)
1128                                 {
1129                                         etl::gaussian_blur_3x3(gauss_surface->begin(),gauss_surface->end());
1130                                         bw-=2,bh-=2;
1131                                 }
1132                                 else
1133                                 if(bw>=1 && bh>=1)
1134                                 {
1135                                         GuassianBlur_2x2(*gauss_surface);
1136                                         bw--,bh--;
1137                                 }
1138                         }
1139
1140                         while(bw)
1141                         {
1142                                 if(!blurcall.amount_complete(max-(bw+bh),max))return false;
1143                                 if(bw>=2)
1144                                 {
1145                                         GuassianBlur_3x1(*gauss_surface);
1146                                         bw-=2;
1147                                 }
1148                                 else
1149                                 if(bw>=1)
1150                                 {
1151                                         GuassianBlur_2x1(*gauss_surface);
1152                                         bw--;
1153                                 }
1154                         }
1155
1156                         while(bh)
1157                         {
1158                                 if(!blurcall.amount_complete(max-(bw+bh),max))return false;
1159                                 if(bh>=2)
1160                                 {
1161                                         GuassianBlur_1x3(*gauss_surface);
1162                                         bh-=2;
1163                                 }
1164                                 else
1165                                 if(bh>=1)
1166                                 {
1167                                         GuassianBlur_1x2(*gauss_surface);
1168                                         bh--;
1169                                 }
1170                         }
1171
1172                         delete [] SC0;
1173                         delete [] SC1;
1174                         delete [] SC2;
1175                         delete [] SC3;
1176
1177                         /*if(get_amount()!=1.0 || get_blend_method()!=Color::BLEND_STRAIGHT)
1178                         {
1179                                 int x,y;
1180                                 for(y=0;y<renddesc.get_h();y++)
1181                                         for(x=0;x<renddesc.get_w();x++)
1182                                                 worksurface[y][x]=Color::blend(temp_surface[y][x],worksurface[y][x],get_amount(),get_blend_method());
1183                         }*/
1184                 }
1185                 break;
1186
1187                 default:
1188                 break;
1189         }
1190
1191         //be sure the surface is of the correct size
1192         //surface->set_wh(renddesc.get_w(),renddesc.get_h());
1193         out.set_wh(w,h);
1194
1195         //divide out the alpha - don't need to cause we rock
1196         out = worksurface;
1197
1198         //we are FRIGGGIN done....
1199         blurcall.amount_complete(100,100);
1200
1201         return true;
1202 }
1203
1204 /* === E N T R Y P O I N T ================================================= */