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 ** Copyright (c) 2012-2013 Carlos López
10 **
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
15 **
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
20 ** \endlegal
21 */
22 /* ========================================================================= */
23
24 /* === H E A D E R S ======================================================= */
25
26 #ifdef USING_PCH
27 # include "pch.h"
28 #else
29 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32
33 #include <stdexcept>
34
35 #include <ETL/boxblur>
36 #include <ETL/gaussian>
37
38 #include "blur.h"
39
40 #include "general.h"
41 #include <synfig/localization.h>
42
43 #endif
44
45 /* === U S I N G =========================================================== */
46
47 using namespace std;
48 using namespace etl;
49 using namespace synfig;
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
59 synfig::Real
get_size_amplifier(int type)60 Blur::get_size_amplifier(int type)
61 {
62 // measured values
63 switch(type)
64 {
65 case Blur::BOX:
66 return 19.362962/9.182808*19.362962/20.634363;
67 case Blur::FASTGAUSSIAN:
68 return 20.297409/6.309251*20.297409/21.081510*20.297409/21.513471;
69 case Blur::CROSS:
70 return 19.362962/9.182808*19.362962/20.634363;
71 //case Blur::GAUSSIAN:
72 // return 20.297409/0.417297*20.297409/9.851342*20.297409/12.328201;
73 case Blur::DISC:
74 return 17.821498/8.778783*17.821498/17.640771;
75 }
76 return 1.0;
77 }
78
79
operator ()(const Point & pos) const80 Point Blur::operator()(const Point &pos) const
81 {
82 Point blurpos(pos);
83
84 switch(type)
85 {
86 case CROSS:
87 if(rand()%2)
88 {
89 if(size[0])
90 blurpos[0]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[0];
91 }
92 else
93 {
94 if(size[1])
95 blurpos[1]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[1];
96 }
97 break;
98
99 case DISC:
100 {
101 Angle theta=Angle::rotations((float)rand()/(float)RAND_MAX);
102 Vector::value_type mag=(float)rand()/(float)RAND_MAX;
103 Vector vect((float)Angle::cos(theta).get()*mag,(float)Angle::sin(theta).get()*mag);
104
105 blurpos[0]+=vect[0]*size[0];
106 blurpos[1]+=vect[1]*size[1];
107 }
108 break;
109
110 case FASTGAUSSIAN:
111 case GAUSSIAN:
112 // Not quite a true gaussian blur,
113 // but the results are close enough for me.
114 if(size[0])
115 {
116 blurpos[0]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[0]*3/4;
117 blurpos[0]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[0]*3/4;
118 }
119 if(size[1])
120 {
121 blurpos[1]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[1]*3/4;
122 blurpos[1]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[1]*3/4;
123 }
124 break;
125
126 case BOX:
127 default:
128 if(size[0])
129 blurpos[0]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[0];
130 if(size[1])
131 blurpos[1]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[1];
132 break;
133 }
134
135 return blurpos;
136 }
137
operator ()(synfig::Real x,synfig::Real y) const138 Point Blur::operator()(synfig::Real x, synfig::Real y) const
139 {
140 return (*this)(Point(x,y));
141 }
142
143 //blur functions to make my life easier
144
145 template <typename T>
zero()146 static inline T zero()
147 {
148 return (T)0;
149 }
150
151 template <>
zero()152 inline Color zero<Color>()
153 {
154 return Color::alpha();
155 }
156
157 template <>
zero()158 inline CairoColorAccumulator zero<CairoColorAccumulator>()
159 {
160 return CairoColorAccumulator(0);
161 }
162
163 template <typename T,typename AT,class VP>
GaussianBlur_2x2(etl::surface<T,AT,VP> & surface)164 static void GaussianBlur_2x2(etl::surface<T,AT,VP> &surface)
165 {
166 int x,y;
167 AT Tmp1,Tmp2,SR0;
168
169 AT *SC0=new AT[surface.get_w()];
170
171 memcpy(SC0,surface[0],surface.get_w()*sizeof(AT));
172
173 for(y=0;y<surface.get_h();y++)
174 {
175 SR0=surface[y][0];
176 for(x=0;x<surface.get_w();x++)
177 {
178 Tmp1=(AT)(surface[y][x]);
179 Tmp2=SR0+Tmp1;
180 SR0=Tmp1;
181 surface[y][x]=(SC0[x]+Tmp2)/4;
182 SC0[x]=Tmp2;
183 }
184 }
185 delete [] SC0;
186 }
187
188 template <typename T,typename AT,class VP>
GaussianBlur_3x3(etl::surface<T,AT,VP> & surface)189 static void GaussianBlur_3x3(etl::surface<T,AT,VP> &surface)
190 {
191 int x,y,u,v,w,h;
192 AT Tmp1,Tmp2,SR0,SR1;
193
194 w=surface.get_w();
195 h=surface.get_h();
196
197 AT *SC0=new AT[w+1];
198 AT *SC1=new AT[w+1];
199
200 // Setup the row buffers
201 for(x=0;x<w;x++)SC0[x]=(AT)(surface[0][x])*4;
202
203 for(y=0;y<=h;y++)
204 {
205 if(y>=h)
206 v=h-1;
207 else
208 v=y;
209
210 SR0=SR1=surface[y][0];
211 for(x=0;x<=w;x++)
212 {
213 if(x>=w)
214 u=w-1;
215 else
216 u=x;
217
218 // Row Machine
219 Tmp1=surface[v][u];
220 Tmp2=SR0+Tmp1;
221 SR0=Tmp1;
222 Tmp1=SR1+Tmp2;
223 SR1=Tmp2;
224
225 // Column Machine
226 Tmp2=SC0[x]+Tmp1;
227 SC0[x]=Tmp1;
228 if(y&&x)
229 surface[y-1][x-1]=(SC1[x]+Tmp2)/16;
230 SC1[x]=Tmp2;
231 }
232 }
233
234 delete [] SC0;
235 delete [] SC1;
236 }
237
238 template <typename T,typename AT,class VP>
GaussianBlur_5x5_(etl::surface<T,AT,VP> & surface,AT * SC0,AT * SC1,AT * SC2,AT * SC3)239 inline static void GaussianBlur_5x5_(etl::surface<T,AT,VP> &surface,AT *SC0,AT *SC1,AT *SC2,AT *SC3)
240 {
241 int x,y,u,v,w,h;
242 AT Tmp1,Tmp2,SR0,SR1,SR2,SR3;
243
244 w=surface.get_w();
245 h=surface.get_h();
246
247 // Setup the row buffers
248 for(x=0;x<w;x++)SC0[x+2]=(AT)(surface[0][x])*24;
249
250 for(y=0;y<h+2;y++)
251 {
252 if(y>=h)
253 v=h-1;
254 else
255 v=y;
256
257 SR0=SR1=SR2=SR3=0;
258 SR0=(AT)(surface[v][0])*1.5;
259 for(x=0;x<w+2;x++)
260 {
261 if(x>=w)
262 u=w-1;
263 else
264 u=x;
265
266 // Row Machine
267 Tmp1=surface[v][u];
268 Tmp2=SR0+Tmp1;
269 SR0=Tmp1;
270 Tmp1=SR1+Tmp2;
271 SR1=Tmp2;
272 Tmp2=SR2+Tmp1;
273 SR2=Tmp1;
274 Tmp1=SR3+Tmp2;
275 SR3=Tmp2;
276
277 // Column Machine
278 Tmp2=SC0[x]+Tmp1;
279 SC0[x]=Tmp1;
280 Tmp1=SC1[x]+Tmp2;
281 SC1[x]=Tmp2;
282 Tmp2=SC2[x]+Tmp1;
283 SC2[x]=Tmp1;
284 if(y>1&&x>1)
285 surface[y-2][x-2]=(SC3[x]+Tmp2)/256;
286 SC3[x]=Tmp2;
287 }
288 }
289
290 }
291
292 template <typename T,typename AT,class VP>
GaussianBlur_5x5(etl::surface<T,AT,VP> & surface)293 inline static void GaussianBlur_5x5(etl::surface<T,AT,VP> &surface)
294 {
295 int w=surface.get_w();
296
297 AT *SC0=new AT[w+2];
298 AT *SC1=new AT[w+2];
299 AT *SC2=new AT[w+2];
300 AT *SC3=new AT[w+2];
301
302 GaussianBlur_5x5_(surface,SC0,SC1,SC2,SC3);
303
304 delete [] SC0;
305 delete [] SC1;
306 delete [] SC2;
307 delete [] SC3;
308 }
309
310 template <typename T,typename AT,class VP>
GaussianBlur_nxn(etl::surface<T,AT,VP> & surface,int n)311 static void GaussianBlur_nxn(etl::surface<T,AT,VP> &surface,int n)
312 {
313 int x,y,u,v,w,h;
314 int half_n=n/2,i;
315 float inv_divisor=pow(2.0,(n-1));
316 AT Tmp1,Tmp2;
317 inv_divisor=1.0/(inv_divisor*inv_divisor);
318
319 w=surface.get_w();
320 h=surface.get_h();
321
322 AT SR[n-1];
323 AT *SC[n-1];
324
325 for(i=0;i<n-1;i++)
326 {
327 SC[i]=new AT[w+half_n];
328 if(!SC[i])
329 {
330 throw(runtime_error(strprintf(__FILE__":%d:Malloc failure",__LINE__)));
331 return;
332 }
333 }
334
335 // Setup the first row
336 // for(x=0;x<w;x++)SC[0][x+half_n]=surface[0][x]*550.0;//*pow(2.0,(n-1))*(2.0/n);
337
338 for(y=0;y<h+half_n;y++)
339 {
340 if(y>=h)
341 v=h-1;
342 else
343 v=y;
344
345 if(y!=0)
346 memset(SR,0,(n-1)*sizeof(AT));
347
348 // SR[0]=surface[v][0]*(2.0-1.9/n);
349
350 for(x=0;x<w+half_n;x++)
351 {
352 if(x>=w)
353 u=w-1;
354 else
355 u=x;
356
357 Tmp1=surface[v][u];
358 // Row Machine
359 for(i=0;i<half_n;i++)
360 {
361 Tmp2=SR[i*2]+Tmp1;
362 SR[i*2]=Tmp1;
363 Tmp1=SR[i*2+1]+Tmp2;
364 SR[i*2+1]=Tmp2;
365 }
366
367 // Column Machine
368 for(i=0;i<half_n-1;i++)
369 {
370 Tmp2=SC[i*2][x]+Tmp1;
371 SC[i*2][x]=Tmp1;
372 Tmp1=SC[i*2+1][x]+Tmp2;
373 SC[i*2+1][x]=Tmp2;
374 }
375 Tmp2=SC[n-3][x]+Tmp1;
376 SC[n-3][x]=Tmp1;
377 if(y>=half_n&&x>=half_n)
378 surface[y-half_n][x-half_n]=(SC[n-2][x]+Tmp2)*inv_divisor;
379 SC[n-2][x]=Tmp2;
380 }
381 }
382
383 for(i=0;i<n-1;i++)
384 delete [] SC[i];
385 }
386
387 template <typename T,typename AT,class VP>
GaussianBlur_2x1(etl::surface<T,AT,VP> & surface)388 static void GaussianBlur_2x1(etl::surface<T,AT,VP> &surface)
389 {
390 int x,y;
391 AT Tmp1,Tmp2,SR0;
392
393 for(y=0;y<surface.get_h();y++)
394 {
395 SR0=surface[y][0];
396 for(x=0;x<surface.get_w();x++)
397 {
398 Tmp1=surface[y][x];
399 Tmp2=SR0+Tmp1;
400 SR0=Tmp1;
401 surface[y][x]=(Tmp2)/2;
402 }
403 }
404 }
405
406 template <typename T,typename AT,class VP>
GaussianBlur_3x1(etl::surface<T,AT,VP> & surface)407 static void GaussianBlur_3x1(etl::surface<T,AT,VP> &surface)
408 {
409 int x,y;
410 AT Tmp1,Tmp2,SR0,SR1;
411
412 for(y=0;y<surface.get_h();y++)
413 {
414 SR0=SR1=surface[y][0];
415 for(x=0;x<surface.get_w();x++)
416 {
417 // Row Machine
418 Tmp1=surface[y][x];
419 Tmp2=SR0+Tmp1;
420 SR0=Tmp1;
421 Tmp1=SR1+Tmp2;
422 SR1=Tmp2;
423
424 if(x)
425 surface[y][x-1]=(Tmp1)/4;
426 }
427 }
428 }
429
430 template <typename T,typename AT,class VP>
GaussianBlur_1x2(etl::surface<T,AT,VP> & surface)431 static void GaussianBlur_1x2(etl::surface<T,AT,VP> &surface)
432 {
433 int x,y;
434 AT Tmp1,Tmp2,SR0;
435
436 for(x=0;x<surface.get_w();x++)
437 {
438 SR0 = zero<AT>();
439 for(y=0;y<surface.get_h();y++)
440 {
441 Tmp1=surface[y][x];
442 Tmp2=SR0+Tmp1;
443 SR0=Tmp1;
444 surface[y][x]=(Tmp2)/2;
445 }
446 }
447 }
448
449 template <typename T,typename AT,class VP>
GaussianBlur_1x3(etl::surface<T,AT,VP> & surface)450 static void GaussianBlur_1x3(etl::surface<T,AT,VP> &surface)
451 {
452 int x,y;
453 AT Tmp1,Tmp2,SR0,SR1;
454
455 for(x=0;x<surface.get_w();x++)
456 {
457 SR0=SR1=surface[0][x];
458 for(y=0;y<surface.get_h();y++)
459 {
460 // Row Machine
461 Tmp1=surface[y][x];
462 Tmp2=SR0+Tmp1;
463 SR0=Tmp1;
464 Tmp1=SR1+Tmp2;
465 SR1=Tmp2;
466
467 if(y)
468 surface[y-1][x]=(Tmp1)/4;
469 }
470 }
471 }
472
473 //THE GOOD ONE!!!!!!!!!
operator ()(const Surface & surface,const Vector & resolution,Surface & out) const474 bool Blur::operator()(const Surface &surface,
475 const Vector &resolution,
476 Surface &out) const
477 {
478 int w = surface.get_w(),
479 h = surface.get_h();
480
481 if(w == 0 || h == 0 || resolution[0] == 0 || resolution[1] == 0) return false;
482
483 const Real pw = resolution[0]/w,
484 ph = resolution[1]/h;
485
486 int halfsizex = (int) (abs(size[0]*.5/pw) + 1),
487 halfsizey = (int) (abs(size[1]*.5/ph) + 1);
488
489 int x,y;
490
491 SuperCallback blurcall(cb,0,5000,5000);
492
493 Surface worksurface(w,h);
494
495 //synfig::info("Blur: check surface = %s", surface_valid(surface)?"true":"false");
496
497 // Premultiply the alpha
498 for(y=0;y<h;y++)
499 {
500 for(x=0;x<w;x++)
501 {
502 Color a = surface[y][x];
503 a.set_r(a.get_r()*a.get_a());
504 a.set_g(a.get_g()*a.get_a());
505 a.set_b(a.get_b()*a.get_a());
506 worksurface[y][x] = a;
507 }
508 }
509
510 switch(type)
511 {
512 case Blur::DISC: // D I S C ----------------------------------------------------------
513 {
514 int bw = halfsizex;
515 int bh = halfsizey;
516
517 if(size[0] && size[1] && w*h>2)
518 {
519 int x2,y2;
520 Surface tmp_surface(worksurface);
521
522 for(y=0;y<h;y++)
523 {
524 for(x=0;x<w;x++)
525 {
526 //accumulate all the pixels in an ellipse of w,h about the current pixel
527 Color color=Color::alpha();
528 int total=0;
529
530 for(y2=-bh;y2<=bh;y2++)
531 {
532 for(x2=-bw;x2<=bw;x2++)
533 {
534 //get the floating point distance away from the origin pixel in relative coords
535 float tmp_x=(float)x2/bw;
536 float tmp_y=(float)y2/bh;
537 tmp_x*=tmp_x;
538 tmp_y*=tmp_y;
539
540 //ignore if it's outside of the disc
541 if( tmp_x+tmp_y>1.0)
542 continue;
543
544 //cap the pixel indices to inside the surface
545 int u= x+x2,
546 v= y+y2;
547
548 if( u < 0 ) u = 0;
549 if( u >= w ) u = w-1;
550
551 if( v < 0 ) v = 0;
552 if( v >= h ) v = h-1;
553
554 //accumulate the color, and # of pixels added in
555 color += tmp_surface[v][u];
556 total++;
557 }
558 }
559
560 //blend the color with the original color
561 //if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
562 worksurface[y][x]=color/total;
563 //else
564 // worksurface[y][x]=Color::blend(color/total,tmp_surface[y][x],get_amount(),get_blend_method());
565 }
566 if(!blurcall.amount_complete(y,h))
567 {
568 //if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
569 return false;
570 }
571 }
572 break;
573 }
574
575 //if we don't qualify for disc blur just use box blur
576 }
577
578 case Blur::BOX: // B O X -------------------------------------------------------
579 {
580 //horizontal part
581 //synfig::info("Blur: Starting Box blur (surface valid %d)", (int)surface_valid(worksurface));
582
583 Surface temp_surface;
584 temp_surface.set_wh(w,h);
585
586 if(size[0])
587 {
588 int length = halfsizex;
589 length=std::max(1,length);
590
591 //synfig::info("Blur: hbox blur work -> temp %d", length);
592 etl::hbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface.begin());
593 }
594 else temp_surface = worksurface;
595 //synfig::info("Blur: hbox finished");
596
597 //vertical part
598 //Surface temp_surface2;
599 //temp_surface2.set_wh(w,h);
600
601 if(size[1])
602 {
603 int length = halfsizey;
604 length = std::max(1,length);
605
606 //synfig::info("Blur: vbox blur temp -> work %d",length);
607 etl::vbox_blur(temp_surface.begin(),temp_surface.end(),length,worksurface.begin());
608 }
609 else worksurface = temp_surface;
610 //synfig::info("Blur: vbox finished");
611
612 //blend with the original surface
613 /*int x,y;
614 for(y=0;y<h;y++)
615 {
616 for(x=0;x<w;x++)
617 {
618 worksurface[y][x]=temp_surface2[y][x];//Color::blend(temp_surface2[y][x],worksurface[y][x],get_amount(),get_blend_method());
619 }
620 }*/
621 }
622 break;
623
624 case Blur::FASTGAUSSIAN: // F A S T G A U S S I A N ----------------------------------------------
625 {
626 //fast gaussian is treated as a 3x3 type of thing, except expanded to work with the length
627
628 /* 1 2 1
629 2 4 2
630 1 2 1
631 */
632
633 Surface temp_surface;
634 temp_surface.set_wh(w,h);
635
636 //Surface temp_surface2;
637 //temp_surface2.set_wh(w,h);
638
639 //horizontal part
640 if(size[0])
641 {
642 Real length=abs((float)w/(resolution[0]))*size[0]*0.5+1;
643 length=std::max(1.0,length);
644
645 //two box blurs produces: 1 2 1
646 etl::hbox_blur(worksurface.begin(),w,h,(int)(length*3/4),temp_surface.begin());
647 etl::hbox_blur(temp_surface.begin(),w,h,(int)(length*3/4),worksurface.begin());
648 }
649 //else temp_surface2=worksurface;
650
651 //vertical part
652 if(size[1])
653 {
654 Real length=abs((float)h/(resolution[1]))*size[1]*0.5+1;
655 length=std::max(1.0,length);
656
657 //two box blurs produces: 1 2 1 on the horizontal 1 2 1
658 etl::vbox_blur(worksurface.begin(),w,h,(int)(length*3/4),temp_surface.begin());
659 etl::vbox_blur(temp_surface.begin(),w,h,(int)(length*3/4),worksurface.begin());
660 }
661 //else temp_surface2=temp_surface2;
662
663 /*int x,y;
664 for(y=0;y<h;y++)
665 {
666 for(x=0;x<w;x++)
667 {
668 worksurface[y][x]=temp_surface2[y][x];//Color::blend(temp_surface2[y][x],worksurface[y][x],get_amount(),get_blend_method());
669 }
670 }*/
671 }
672 break;
673
674 case Blur::CROSS: // C R O S S -------------------------------------------------------
675 {
676 //horizontal part
677 Surface temp_surface;
678 temp_surface.set_wh(worksurface.get_w(),worksurface.get_h());
679
680 if(size[0])
681 {
682 int length = halfsizex;
683 length = std::max(1,length);
684
685 etl::hbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface.begin());
686 }
687 else temp_surface = worksurface;
688
689 //vertical part
690 Surface temp_surface2;
691 temp_surface2.set_wh(worksurface.get_w(),worksurface.get_h());
692
693 if(size[1])
694 {
695 int length = halfsizey;
696 length = std::max(1,length);
697
698 etl::vbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface2.begin());
699 }
700 else temp_surface2 = worksurface;
701
702 //blend the two together
703 int x,y;
704
705 for(y=0;y<h;y++)
706 {
707 for(x=0;x<w;x++)
708 {
709 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());
710 }
711 }
712
713 break;
714 }
715
716 case Blur::GAUSSIAN: // G A U S S I A N ----------------------------------------------
717 {
718 #ifndef GAUSSIAN_ADJUSTMENT
719 #define GAUSSIAN_ADJUSTMENT (0.05)
720 #endif
721
722 Real pw = (Real)w/(resolution[0]);
723 Real ph = (Real)h/(resolution[1]);
724
725 Surface temp_surface;
726 Surface *gauss_surface;
727
728 //synfig::warning("Didn't crash yet b1");
729
730 //if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
731 gauss_surface = &worksurface;
732 /*else
733 {
734 temp_surface = worksurface;
735 gauss_surface = &temp_surface;
736 }*/
737
738 /* Squaring the pw and ph values
739 is necessary to insure consistent
740 results when rendered to different
741 resolutions.
742 Unfortunately, this automatically
743 squares our rendertime.
744 There has got to be a faster way...
745 */
746 pw=pw*pw;
747 ph=ph*ph;
748
749 int bw = (int)(abs(pw)*size[0]*GAUSSIAN_ADJUSTMENT+0.5);
750 int bh = (int)(abs(ph)*size[1]*GAUSSIAN_ADJUSTMENT+0.5);
751 int max=bw+bh;
752
753 ColorAccumulator *SC0=new ColorAccumulator[w+2];
754 ColorAccumulator *SC1=new ColorAccumulator[w+2];
755 ColorAccumulator *SC2=new ColorAccumulator[w+2];
756 ColorAccumulator *SC3=new ColorAccumulator[w+2];
757
758 //synfig::warning("Didn't crash yet b2");
759 //int i = 0;
760
761 while(bw&&bh)
762 {
763 if(!blurcall.amount_complete(max-(bw+bh),max))return false;
764
765 if(bw>=4 && bh>=4)
766 {
767 etl::gaussian_blur_5x5_(gauss_surface->begin(),gauss_surface->get_w(),gauss_surface->get_h(),SC0,SC1,SC2,SC3);
768 bw-=4,bh-=4;
769 }
770 else
771 if(bw>=2 && bh>=2)
772 {
773 etl::gaussian_blur_3x3(gauss_surface->begin(),gauss_surface->end());
774 bw-=2,bh-=2;
775 }
776 else
777 if(bw>=1 && bh>=1)
778 {
779 GaussianBlur_2x2(*gauss_surface);
780 bw--,bh--;
781 }
782
783 //synfig::warning("Didn't crash yet bi - %d",i++);
784 }
785 while(bw)
786 {
787 if(!blurcall.amount_complete(max-(bw+bh),max))return false;
788 if(bw>=2)
789 {
790 GaussianBlur_3x1(*gauss_surface);
791 bw-=2;
792 }
793 else
794 if(bw>=1)
795 {
796 GaussianBlur_2x1(*gauss_surface);
797 bw--;
798 }
799 //synfig::warning("Didn't crash yet bi - %d",i++);
800 }
801 while(bh)
802 {
803 if(!blurcall.amount_complete(max-(bw+bh),max))return false;
804 if(bh>=2)
805 {
806 GaussianBlur_1x3(*gauss_surface);
807 bh-=2;
808 }
809 else
810 if(bh>=1)
811 {
812 GaussianBlur_1x2(*gauss_surface);
813 bh--;
814 }
815 //synfig::warning("Didn't crash yet bi - %d",i++);
816 }
817
818 delete [] SC0;
819 delete [] SC1;
820 delete [] SC2;
821 delete [] SC3;
822
823 /*if(get_amount()!=1.0 || get_blend_method()!=Color::BLEND_STRAIGHT)
824 {
825 int x,y;
826 for(y=0;y<renddesc.get_h();y++)
827 for(x=0;x<renddesc.get_w();x++)
828 worksurface[y][x]=Color::blend(temp_surface[y][x],worksurface[y][x],get_amount(),get_blend_method());
829 }*/
830 //synfig::warning("Didn't crash yet b end",i++);
831 }
832 break;
833
834 default:
835 break;
836 }
837
838 // Scale up the alpha
839
840 //be sure the surface is of the correct size
841 //surface->set_wh(renddesc.get_w(),renddesc.get_h());
842 out.set_wh(w,h);
843
844 //divide out the alpha
845 for(y=0;y<h;y++)
846 {
847 for(x=0;x<w;x++)
848 {
849 Color a = worksurface[y][x];
850 if(a.get_a())
851 {
852 a.set_r(a.get_r()/a.get_a());
853 a.set_g(a.get_g()/a.get_a());
854 a.set_b(a.get_b()/a.get_a());
855 out[y][x]=a;
856 }
857 else out[y][x]=Color::alpha();
858 }
859 }
860
861 //we are FRIGGGIN done....
862 blurcall.amount_complete(100,100);
863
864 return true;
865 }
866
867 //////
operator ()(cairo_surface_t * surface,const Vector & resolution,cairo_surface_t * out) const868 bool Blur::operator()(cairo_surface_t *surface,
869 const Vector &resolution,
870 cairo_surface_t *out) const
871 {
872
873 CairoSurface cairosurface(surface);
874 if(!cairosurface.map_cairo_image())
875 {
876 synfig::info("cairosurface map cairo image failed");
877 return false;
878 }
879
880 int w = cairosurface.get_w(),
881 h = cairosurface.get_h();
882
883 if(w == 0 || h == 0 || resolution[0] == 0 || resolution[1] == 0)
884 {
885 cairosurface.unmap_cairo_image();
886 return false;
887 }
888
889 const Real pw = resolution[0]/w,
890 ph = resolution[1]/h;
891
892 int halfsizex = (int) (abs(size[0]*.5/pw) + 1),
893 halfsizey = (int) (abs(size[1]*.5/ph) + 1);
894
895 int x,y;
896
897 SuperCallback blurcall(cb,0,5000,5000);
898
899 CairoSurface cairoout(out);
900 if(!cairoout.map_cairo_image())
901 {
902 synfig::info("cairoout map cairo image failed");
903 cairosurface.unmap_cairo_image();
904 return false;
905 }
906
907 switch(type)
908 {
909 case Blur::DISC: // D I S C ----------------------------------------------------------
910 {
911 int bw = halfsizex;
912 int bh = halfsizey;
913
914 if(size[0] && size[1] && w*h>2)
915 {
916 int x2,y2;
917
918 for(y=0;y<h;y++)
919 {
920 for(x=0;x<w;x++)
921 {
922 //accumulate all the pixels in an ellipse of w,h about the current pixel
923 Color color=Color::alpha();
924 int total=0;
925
926 for(y2=-bh;y2<=bh;y2++)
927 {
928 for(x2=-bw;x2<=bw;x2++)
929 {
930 //get the floating point distance away from the origin pixel in relative coords
931 float tmp_x=(float)x2/bw;
932 float tmp_y=(float)y2/bh;
933 tmp_x*=tmp_x;
934 tmp_y*=tmp_y;
935
936 //ignore if it's outside of the disc
937 if( tmp_x+tmp_y>1.0)
938 continue;
939
940 //cap the pixel indices to inside the surface
941 int u= x+x2,
942 v= y+y2;
943
944 if( u < 0 ) u = 0;
945 if( u >= w ) u = w-1;
946
947 if( v < 0 ) v = 0;
948 if( v >= h ) v = h-1;
949
950 //accumulate the color, and # of pixels added in
951 color += Color(cairosurface[v][u]);
952 total++;
953 }
954 }
955
956 //blend the color with the original color
957 cairoout[y][x]=CairoColor(color/total);
958 }
959 if(!blurcall.amount_complete(y,h))
960 {
961 if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
962 cairosurface.unmap_cairo_image();
963 cairoout.unmap_cairo_image();
964 return false;
965 }
966 }
967 break;
968 }
969 //if we don't qualify for disc blur just use box blur
970 }
971
972 case Blur::BOX: // B O X -------------------------------------------------------
973 {
974 cairo_surface_t* temp=cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR_ALPHA, w, h);
975 CairoSurface cairotemp(temp);
976 if(!cairotemp.map_cairo_image())
977 {
978 synfig::info("cairotemp map cairo image failed");
979 return false;
980 }
981 //horizontal part
982 if(size[0])
983 {
984 int length = halfsizex;
985 length=std::max(1,length);
986 etl::hbox_blur(cairosurface.begin(),cairosurface.end(),length,cairotemp.begin());
987 }
988 else cairotemp.copy(cairosurface);
989
990 //vertical part
991 if(size[1])
992 {
993 int length = halfsizey;
994 length = std::max(1,length);
995 etl::vbox_blur(cairotemp.begin(),cairotemp.end(),length,cairoout.begin());
996 }
997 else cairoout.copy(cairotemp);
998 cairotemp.unmap_cairo_image();
999 cairo_surface_destroy(temp);
1000 }
1001 break;
1002
1003 case Blur::FASTGAUSSIAN: // F A S T G A U S S I A N ----------------------------------------------
1004 {
1005 //fast gaussian is treated as a 3x3 type of thing, except expanded to work with the length
1006
1007 /* 1 2 1
1008 2 4 2
1009 1 2 1
1010 */
1011 cairo_surface_t* temp=cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR_ALPHA, w, h);
1012 CairoSurface cairotemp(temp);
1013 if(!cairotemp.map_cairo_image())
1014 {
1015 synfig::info("cairotemp map cairo image failed. Fast Gaussian");
1016 return false;
1017 }
1018
1019 //horizontal part
1020 if(size[0])
1021 {
1022 Real length=abs((float)w/(resolution[0]))*size[0]*0.5+1;
1023 length=std::max(1.0,length);
1024
1025 //two box blurs produces: 1 2 1
1026 etl::hbox_blur(cairosurface.begin(),w,h,(int)(length*3/4),cairotemp.begin());
1027 etl::hbox_blur(cairotemp.begin(),w,h,(int)(length*3/4),cairoout.begin());
1028 }
1029 else cairoout.copy(cairosurface);
1030
1031 // Interchange result with temp
1032 cairotemp.copy(cairoout);
1033 //vertical part
1034 if(size[1])
1035 {
1036 Real length=abs((float)h/(resolution[1]))*size[1]*0.5+1;
1037 length=std::max(1.0,length);
1038
1039 //two box blurs produces: 1 2 1 on the horizontal 1 2 1
1040 etl::vbox_blur(cairoout.begin(),w,h,(int)(length*3/4),cairotemp.begin());
1041 etl::vbox_blur(cairotemp.begin(),w,h,(int)(length*3/4),cairoout.begin());
1042 }
1043 else cairoout.copy(cairotemp);
1044 cairotemp.unmap_cairo_image();
1045 cairo_surface_destroy(temp);
1046 }
1047 break;
1048
1049 case Blur::CROSS: // C R O S S -------------------------------------------------------
1050 {
1051 //horizontal part
1052 cairo_surface_t* temp=cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR_ALPHA, w, h);
1053 CairoSurface cairotemp(temp);
1054 if(!cairotemp.map_cairo_image())
1055 {
1056 synfig::info("cairotemp map cairo image failed. Cross");
1057 cairo_surface_destroy(temp);
1058 return false;
1059 }
1060
1061 if(size[0])
1062 {
1063 int length = halfsizex;
1064 length = std::max(1,length);
1065
1066 etl::hbox_blur(cairosurface.begin(),cairosurface.end(),length,cairotemp.begin());
1067 }
1068 else cairotemp.copy(cairosurface);
1069
1070 //vertical part
1071 cairo_surface_t* temp2=cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR_ALPHA, w, h);
1072 CairoSurface cairotemp2(temp2);
1073 if(!cairotemp2.map_cairo_image())
1074 {
1075 synfig::info("cairotemp2 map cairo image failed. Cross");
1076 cairotemp.unmap_cairo_image();
1077 cairo_surface_destroy(temp);
1078 cairo_surface_destroy(temp2);
1079 return false;
1080 }
1081
1082 if(size[1])
1083 {
1084 int length = halfsizey;
1085 length = std::max(1,length);
1086
1087 etl::vbox_blur(cairosurface.begin(),cairosurface.end(),length,cairotemp2.begin());
1088 }
1089 else cairotemp2.copy(cairosurface);
1090
1091 //blend the two together
1092 int x,y;
1093
1094 for(y=0;y<h;y++)
1095 {
1096 for(x=0;x<w;x++)
1097 {
1098 cairoout[y][x] = cairotemp[y][x]*0.5+cairotemp2[y][x]*0.5;
1099 }
1100 }
1101 cairotemp.unmap_cairo_image();
1102 cairo_surface_destroy(temp);
1103 cairotemp2.unmap_cairo_image();
1104 cairo_surface_destroy(temp2);
1105 break;
1106 }
1107
1108 case Blur::GAUSSIAN: // G A U S S I A N ----------------------------------------------
1109 {
1110 #ifndef GAUSSIAN_ADJUSTMENT
1111 #define GAUSSIAN_ADJUSTMENT (0.05)
1112 #endif
1113
1114 Real pw = (Real)w/(resolution[0]);
1115 Real ph = (Real)h/(resolution[1]);
1116
1117 CairoSurface *gauss_surface;
1118 cairoout.copy(cairosurface);
1119 gauss_surface = &cairoout;
1120 /* Squaring the pw and ph values
1121 is necessary to insure consistent
1122 results when rendered to different
1123 resolutions.
1124 Unfortunately, this automatically
1125 squares our rendertime.
1126 There has got to be a faster way...
1127 */
1128 pw=pw*pw;
1129 ph=ph*ph;
1130
1131 int bw = (int)(abs(pw)*size[0]*GAUSSIAN_ADJUSTMENT+0.5);
1132 int bh = (int)(abs(ph)*size[1]*GAUSSIAN_ADJUSTMENT+0.5);
1133 int max=bw+bh;
1134
1135 CairoColorAccumulator *SC0=new class CairoColorAccumulator[w+2];
1136 CairoColorAccumulator *SC1=new class CairoColorAccumulator[w+2];
1137 CairoColorAccumulator *SC2=new class CairoColorAccumulator[w+2];
1138 CairoColorAccumulator *SC3=new class CairoColorAccumulator[w+2];
1139
1140 while(bw&&bh)
1141 {
1142 if(!blurcall.amount_complete(max-(bw+bh),max))return false;
1143
1144 if(bw>=4 && bh>=4)
1145 {
1146 etl::gaussian_blur_5x5_(gauss_surface->begin(),gauss_surface->get_w(),gauss_surface->get_h(),SC0,SC1,SC2,SC3);
1147 bw-=4,bh-=4;
1148 }
1149 else
1150 if(bw>=2 && bh>=2)
1151 {
1152 etl::gaussian_blur_3x3(gauss_surface->begin(),gauss_surface->end());
1153 bw-=2,bh-=2;
1154 }
1155 else
1156 if(bw>=1 && bh>=1)
1157 {
1158 GaussianBlur_2x2(*gauss_surface);
1159 bw--,bh--;
1160 }
1161 }
1162 while(bw)
1163 {
1164 if(!blurcall.amount_complete(max-(bw+bh),max))return false;
1165 if(bw>=2)
1166 {
1167 GaussianBlur_3x1(*gauss_surface);
1168 bw-=2;
1169 }
1170 else
1171 if(bw>=1)
1172 {
1173 GaussianBlur_2x1(*gauss_surface);
1174 bw--;
1175 }
1176 }
1177 while(bh)
1178 {
1179 if(!blurcall.amount_complete(max-(bw+bh),max))return false;
1180 if(bh>=2)
1181 {
1182 GaussianBlur_1x3(*gauss_surface);
1183 bh-=2;
1184 }
1185 else
1186 if(bh>=1)
1187 {
1188 GaussianBlur_1x2(*gauss_surface);
1189 bh--;
1190 }
1191 }
1192
1193 delete [] SC0;
1194 delete [] SC1;
1195 delete [] SC2;
1196 delete [] SC3;
1197 }
1198 break;
1199
1200 default:
1201 break;
1202 }
1203
1204 //we are FRIGGGIN done....
1205 blurcall.amount_complete(100,100);
1206
1207 cairosurface.unmap_cairo_image();
1208 cairoout.unmap_cairo_image();
1209
1210 return true;
1211 }
1212
1213 //////
1214
operator ()(const etl::surface<float> & surface,const synfig::Vector & resolution,etl::surface<float> & out) const1215 bool Blur::operator()(const etl::surface<float> &surface,
1216 const synfig::Vector &resolution,
1217 etl::surface<float> &out) const
1218 {
1219 int w = surface.get_w(),
1220 h = surface.get_h();
1221
1222 if(w == 0 || h == 0 || resolution[0] == 0 || resolution[1] == 0) return false;
1223
1224 const Real pw = resolution[0]/w,
1225 ph = resolution[1]/h;
1226
1227 int halfsizex = (int) (abs(size[0]*.5/pw) + 1),
1228 halfsizey = (int) (abs(size[1]*.5/ph) + 1);
1229 int x,y;
1230
1231 SuperCallback blurcall(cb,0,5000,5000);
1232
1233 etl::surface<float> worksurface(surface);
1234
1235 //don't need to premultiply because we are dealing with ONLY alpha
1236
1237 switch(type)
1238 {
1239 case Blur::DISC: // D I S C ----------------------------------------------------------
1240 {
1241 int bw = halfsizex;
1242 int bh = halfsizey;
1243
1244 if(size[0] && size[1] && w*h>2)
1245 {
1246 int x2,y2;
1247 etl::surface<float> tmp_surface(worksurface);
1248
1249 for(y=0;y<h;y++)
1250 {
1251 for(x=0;x<w;x++)
1252 {
1253 //accumulate all the pixels in an ellipse of w,h about the current pixel
1254 float a = 0;
1255 int total=0;
1256
1257 for(y2=-bh;y2<=bh;y2++)
1258 {
1259 for(x2=-bw;x2<=bw;x2++)
1260 {
1261 //get the floating point distance away from the origin pixel in relative coords
1262 float tmp_x=(float)x2/bw;
1263 float tmp_y=(float)y2/bh;
1264 tmp_x*=tmp_x;
1265 tmp_y*=tmp_y;
1266
1267 //ignore if it's outside of the disc
1268 if( tmp_x+tmp_y>1.0)
1269 continue;
1270
1271 //cap the pixel indices to inside the surface
1272 int u= x+x2,
1273 v= y+y2;
1274
1275 if( u < 0 ) u = 0;
1276 if( u >= w ) u = w-1;
1277
1278 if( v < 0 ) v = 0;
1279 if( v >= h ) v = h-1;
1280
1281 //accumulate the color, and # of pixels added in
1282 a += tmp_surface[v][u];
1283 total++;
1284 }
1285 }
1286
1287 //blend the color with the original color
1288 //if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
1289 worksurface[y][x]=a/total;
1290 //else
1291 // worksurface[y][x]=Color::blend(color/total,tmp_surface[y][x],get_amount(),get_blend_method());
1292 }
1293 if(!blurcall.amount_complete(y,h))
1294 {
1295 //if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
1296 return false;
1297 }
1298 }
1299 break;
1300 }
1301
1302 //if we don't qualify for disc blur just use box blur
1303 }
1304
1305 case Blur::BOX: // B O X -------------------------------------------------------
1306 {
1307 //horizontal part
1308 etl::surface<float> temp_surface;
1309 temp_surface.set_wh(w,h);
1310
1311 if(size[0])
1312 {
1313 int length = halfsizex;
1314 length=std::max(1,length);
1315
1316 etl::hbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface.begin());
1317 }
1318 else temp_surface = worksurface;
1319
1320 //vertical part
1321 //etl::surface<float> temp_surface2;
1322 //temp_surface2.set_wh(w,h);
1323
1324 if(size[1])
1325 {
1326 int length = halfsizey;
1327 length = std::max(1,length);
1328 etl::vbox_blur(temp_surface.begin(),temp_surface.end(),length,worksurface.begin());
1329 }
1330 else worksurface = temp_surface;
1331
1332 //blend with the original surface
1333 /*int x,y;
1334 for(y=0;y<h;y++)
1335 {
1336 for(x=0;x<w;x++)
1337 {
1338 worksurface[y][x]=temp_surface2[y][x];//Color::blend(temp_surface2[y][x],worksurface[y][x],get_amount(),get_blend_method());
1339 }
1340 }*/
1341 }
1342 break;
1343
1344 case Blur::FASTGAUSSIAN: // F A S T G A U S S I A N ----------------------------------------------
1345 {
1346 //fast gaussian is treated as a 3x3 type of thing, except expanded to work with the length
1347
1348 /* 1 2 1
1349 2 4 2
1350 1 2 1
1351 */
1352
1353 etl::surface<float> temp_surface;
1354 temp_surface.set_wh(w,h);
1355
1356 //etl::surface<float> temp_surface2;
1357 //temp_surface2.set_wh(w,h);
1358
1359 //horizontal part
1360 if(size[0])
1361 {
1362 Real length=abs((float)w/(resolution[0]))*size[0]*0.5+1;
1363 length=std::max(1.0,length);
1364
1365 //two box blurs produces: 1 2 1
1366 etl::hbox_blur(worksurface.begin(),w,h,(int)(length*3/4),temp_surface.begin());
1367 etl::hbox_blur(temp_surface.begin(),w,h,(int)(length*3/4),worksurface.begin());
1368 }
1369 //else temp_surface2=worksurface;
1370
1371 //vertical part
1372 if(size[1])
1373 {
1374 Real length=abs((float)h/(resolution[1]))*size[1]*0.5+1;
1375 length=std::max(1.0,length);
1376
1377 //two box blurs produces: 1 2 1 on the horizontal 1 2 1
1378 etl::vbox_blur(worksurface.begin(),w,h,(int)(length*3/4),temp_surface.begin());
1379 etl::vbox_blur(temp_surface.begin(),w,h,(int)(length*3/4),worksurface.begin());
1380 }
1381 //else temp_surface2=temp_surface2;
1382
1383 /*int x,y;
1384 for(y=0;y<h;y++)
1385 {
1386 for(x=0;x<w;x++)
1387 {
1388 worksurface[y][x]=temp_surface2[y][x];//Color::blend(temp_surface2[y][x],worksurface[y][x],get_amount(),get_blend_method());
1389 }
1390 }*/
1391 }
1392 break;
1393
1394 case Blur::CROSS: // C R O S S -------------------------------------------------------
1395 {
1396 //horizontal part
1397 etl::surface<float> temp_surface;
1398 temp_surface.set_wh(worksurface.get_w(),worksurface.get_h());
1399
1400 if(size[0])
1401 {
1402 int length = halfsizex;
1403 length = std::max(1,length);
1404
1405 etl::hbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface.begin());
1406 }
1407 else temp_surface = worksurface;
1408
1409 //vertical part
1410 etl::surface<float> temp_surface2;
1411 temp_surface2.set_wh(worksurface.get_w(),worksurface.get_h());
1412
1413 if(size[1])
1414 {
1415 int length = halfsizey;
1416 length = std::max(1,length);
1417
1418 etl::vbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface2.begin());
1419 }
1420 else temp_surface2 = worksurface;
1421
1422 //blend the two together
1423 int x,y;
1424
1425 for(y=0;y<h;y++)
1426 {
1427 for(x=0;x<w;x++)
1428 {
1429 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());
1430 }
1431 }
1432
1433 break;
1434 }
1435
1436 case Blur::GAUSSIAN: // G A U S S I A N ----------------------------------------------
1437 {
1438 #ifndef GAUSSIAN_ADJUSTMENT
1439 #define GAUSSIAN_ADJUSTMENT (0.05)
1440 #endif
1441
1442 Real pw = (Real)w/(resolution[0]);
1443 Real ph = (Real)h/(resolution[1]);
1444
1445 //etl::surface<float> temp_surface;
1446 etl::surface<float> *gauss_surface;
1447
1448 //if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
1449 gauss_surface = &worksurface;
1450 /*else
1451 {
1452 temp_surface = worksurface;
1453 gauss_surface = &temp_surface;
1454 }*/
1455
1456 /* Squaring the pw and ph values
1457 is necessary to insure consistent
1458 results when rendered to different
1459 resolutions.
1460 Unfortunately, this automatically
1461 squares our rendertime.
1462 There has got to be a faster way...
1463 */
1464 pw=pw*pw;
1465 ph=ph*ph;
1466
1467 int bw = (int)(abs(pw)*size[0]*GAUSSIAN_ADJUSTMENT+0.5);
1468 int bh = (int)(abs(ph)*size[1]*GAUSSIAN_ADJUSTMENT+0.5);
1469 int max=bw+bh;
1470
1471 float *SC0=new float[w+2];
1472 float *SC1=new float[w+2];
1473 float *SC2=new float[w+2];
1474 float *SC3=new float[w+2];
1475
1476 memset(SC0,0,(w+2)*sizeof(float));
1477 memset(SC0,0,(w+2)*sizeof(float));
1478 memset(SC0,0,(w+2)*sizeof(float));
1479 memset(SC0,0,(w+2)*sizeof(float));
1480
1481 //int i = 0;
1482
1483 while(bw&&bh)
1484 {
1485 if(!blurcall.amount_complete(max-(bw+bh),max))return false;
1486
1487 if(bw>=4 && bh>=4)
1488 {
1489 etl::gaussian_blur_5x5_(gauss_surface->begin(),gauss_surface->get_w(),gauss_surface->get_h(),SC0,SC1,SC2,SC3);
1490 bw-=4,bh-=4;
1491 }
1492 else
1493 if(bw>=2 && bh>=2)
1494 {
1495 etl::gaussian_blur_3x3(gauss_surface->begin(),gauss_surface->end());
1496 bw-=2,bh-=2;
1497 }
1498 else
1499 if(bw>=1 && bh>=1)
1500 {
1501 GaussianBlur_2x2(*gauss_surface);
1502 bw--,bh--;
1503 }
1504 }
1505
1506 while(bw)
1507 {
1508 if(!blurcall.amount_complete(max-(bw+bh),max))return false;
1509 if(bw>=2)
1510 {
1511 GaussianBlur_3x1(*gauss_surface);
1512 bw-=2;
1513 }
1514 else
1515 if(bw>=1)
1516 {
1517 GaussianBlur_2x1(*gauss_surface);
1518 bw--;
1519 }
1520 }
1521
1522 while(bh)
1523 {
1524 if(!blurcall.amount_complete(max-(bw+bh),max))return false;
1525 if(bh>=2)
1526 {
1527 GaussianBlur_1x3(*gauss_surface);
1528 bh-=2;
1529 }
1530 else
1531 if(bh>=1)
1532 {
1533 GaussianBlur_1x2(*gauss_surface);
1534 bh--;
1535 }
1536 }
1537
1538 delete [] SC0;
1539 delete [] SC1;
1540 delete [] SC2;
1541 delete [] SC3;
1542
1543 /*if(get_amount()!=1.0 || get_blend_method()!=Color::BLEND_STRAIGHT)
1544 {
1545 int x,y;
1546 for(y=0;y<renddesc.get_h();y++)
1547 for(x=0;x<renddesc.get_w();x++)
1548 worksurface[y][x]=Color::blend(temp_surface[y][x],worksurface[y][x],get_amount(),get_blend_method());
1549 }*/
1550 }
1551 break;
1552
1553 default:
1554 break;
1555 }
1556
1557 //be sure the surface is of the correct size
1558 //surface->set_wh(renddesc.get_w(),renddesc.get_h());
1559 out.set_wh(w,h);
1560
1561 //divide out the alpha - don't need to cause we rock
1562 out = worksurface;
1563
1564 //we are FRIGGGIN done....
1565 blurcall.amount_complete(100,100);
1566
1567 return true;
1568 }
1569
1570 /* === E N T R Y P O I N T ================================================= */
1571