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