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