1 /* === S Y N F I G ========================================================= */
3 ** \brief Template Header
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
10 ** This package is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU General Public License as
12 ** published by the Free Software Foundation; either version 2 of
13 ** the License, or (at your option) any later version.
15 ** This package is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ** General Public License for more details.
21 /* ========================================================================= */
23 /* === H E A D E R S ======================================================= */
34 #include <synfig/string.h>
35 #include <synfig/time.h>
36 #include <synfig/context.h>
37 #include <synfig/paramdesc.h>
38 #include <synfig/renddesc.h>
39 #include <synfig/surface.h>
40 #include <synfig/value.h>
41 #include <synfig/valuenode.h>
42 #include <synfig/segment.h>
50 using namespace synfig;
55 #define TYPE_FASTGUASSIAN 1
56 #define TYPE_FASTGAUSSIAN 1
58 #define TYPE_GUASSIAN 3
59 #define TYPE_GAUSSIAN 3
63 /* -- G L O B A L S --------------------------------------------------------- */
65 SYNFIG_LAYER_INIT(Layer_Shade);
66 SYNFIG_LAYER_SET_NAME(Layer_Shade,"shade");
67 SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Shade,_("Shade"));
68 SYNFIG_LAYER_SET_CATEGORY(Layer_Shade,_("Stylize"));
69 SYNFIG_LAYER_SET_VERSION(Layer_Shade,"0.2");
70 SYNFIG_LAYER_SET_CVS_ID(Layer_Shade,"$Id$");
72 /* -- F U N C T I O N S ----------------------------------------------------- */
74 inline void clamp(synfig::Vector &v)
80 Layer_Shade::Layer_Shade():
81 Layer_Composite (0.75,Color::BLEND_BEHIND),
83 type(Blur::FASTGAUSSIAN),
84 color(Color::black()),
91 Layer_Shade::set_param(const String ¶m, const ValueBase &value)
93 IMPORT_PLUS(size,clamp(size));
99 return Layer_Composite::set_param(param,value);
103 Layer_Shade::get_param(const String ¶m)const
114 return Layer_Composite::get_param(param);
118 Layer_Shade::get_color(Context context, const Point &pos)const
120 Point blurpos = Blur(size,type)(pos);
122 if(get_amount()==0.0)
123 return context.get_color(pos);
128 shade.set_a(context.get_color(blurpos-offset).get_a());
130 shade.set_a(1.0f-context.get_color(blurpos-offset).get_a());
132 return Color::blend(shade,context.get_color(pos),get_amount(),get_blend_method());
136 Layer_Shade::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
140 const int w = renddesc.get_w(),
141 h = renddesc.get_h();
142 const Real pw = renddesc.get_pw(),
143 ph = renddesc.get_ph();
145 RendDesc workdesc(renddesc);
147 etl::surface<float> blurred;
149 //expand the working surface to accommodate the blur
151 //the expanded size = 1/2 the size in each direction rounded up
152 int halfsizex = (int) (abs(size[0]*.5/pw) + 3),
153 halfsizey = (int) (abs(size[1]*.5/ph) + 3);
155 int offset_u(-round_to_int(offset[0]/pw)),offset_v(-round_to_int(offset[1]/ph));
157 int offset_w(w+abs(offset_u)),offset_h(h+abs(offset_v));
159 workdesc.set_subwindow(
160 offset_u<0?offset_u:0,
161 offset_v<0?offset_v:0,
162 (offset_u>0?offset_u:0)+w,
163 (offset_v>0?offset_v:0)+h
179 //expand by 1/2 size in each direction on either side
186 workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),offset_w+2*max(1,halfsizex),offset_h+2*max(1,halfsizey));
189 case Blur::FASTGAUSSIAN:
196 workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),offset_w+2*max(1,halfsizex),offset_h+2*max(1,halfsizey));
201 #define GAUSSIAN_ADJUSTMENT (0.05)
202 Real pw = (Real)workdesc.get_w()/(workdesc.get_br()[0]-workdesc.get_tl()[0]);
203 Real ph = (Real)workdesc.get_h()/(workdesc.get_br()[1]-workdesc.get_tl()[1]);
208 halfsizex = (int)(abs(pw)*size[0]*GAUSSIAN_ADJUSTMENT+0.5);
209 halfsizey = (int)(abs(ph)*size[1]*GAUSSIAN_ADJUSTMENT+0.5);
211 halfsizex = (halfsizex + 1)/2;
212 halfsizey = (halfsizey + 1)/2;
213 workdesc.set_subwindow( -halfsizex, -halfsizey, offset_w+2*halfsizex, offset_h+2*halfsizey );
218 #define SCALE_FACTOR (64.0)
219 if(/*quality>9 || */size[0]<=pw*SCALE_FACTOR)
221 SuperCallback stageone(cb,0,5000,10000);
222 SuperCallback stagetwo(cb,5000,10000,10000);
224 //callbacks depend on how long the blur takes
225 if(size[0] || size[1])
227 if(type == Blur::DISC)
229 stageone = SuperCallback(cb,0,5000,10000);
230 stagetwo = SuperCallback(cb,5000,10000,10000);
234 stageone = SuperCallback(cb,0,9000,10000);
235 stagetwo = SuperCallback(cb,9000,10000,10000);
240 stageone = SuperCallback(cb,0,9999,10000);
241 stagetwo = SuperCallback(cb,9999,10000,10000);
246 //render the background onto the expanded surface
247 if(!context.accelerated_render(&worksurface,quality,workdesc,&stageone))
250 // Copy over the alpha
251 blurred.set_wh(worksurface.get_w(),worksurface.get_h());
252 for(int j=0;j<worksurface.get_h();j++)
253 for(int i=0;i<worksurface.get_w();i++)
255 blurred[j][i]=worksurface[j][i].get_a();
259 Blur(size,type,&stagetwo)(blurred,workdesc.get_br()-workdesc.get_tl(),blurred);
261 //be sure the surface is of the correct size
262 surface->set_wh(renddesc.get_w(),renddesc.get_h());
264 int u = halfsizex-(offset_u<0?offset_u:0), v = halfsizey-(offset_v<0?offset_v:0);
265 for(y=0;y<renddesc.get_h();y++,v++)
267 u = halfsizex-(offset_u<0?offset_u:0);
268 for(x=0;x<renddesc.get_w();x++,u++)
273 a.set_a(blurred.linear_sample(offset_u+(float)u,offset_v+(float)v));
275 a.set_a(1.0f-blurred.linear_sample(offset_u+(float)u,offset_v+(float)v));
277 if(a.get_a() || get_blend_method()==Color::BLEND_STRAIGHT)
279 (*surface)[y][x]=Color::blend(a,worksurface[v][u],get_amount(),get_blend_method());
281 else (*surface)[y][x] = worksurface[v][u];
288 SuperCallback stageone(cb,0,5000,10000);
289 SuperCallback stagetwo(cb,5000,10000,10000);
291 //callbacks depend on how long the blur takes
292 if(size[0] || size[1])
294 if(type == Blur::DISC)
296 stageone = SuperCallback(cb,0,5000,10000);
297 stagetwo = SuperCallback(cb,5000,10000,10000);
301 stageone = SuperCallback(cb,0,9000,10000);
302 stagetwo = SuperCallback(cb,9000,10000,10000);
307 stageone = SuperCallback(cb,0,9999,10000);
308 stagetwo = SuperCallback(cb,9999,10000,10000);
311 int fw(floor_to_int(abs(size[0]/(pw*SCALE_FACTOR)))+1);
312 int fh(floor_to_int(abs(size[1]/(ph*SCALE_FACTOR)))+1);
313 int tmpw(round_to_int((float)workdesc.get_w()/fw)),tmph(round_to_int((float)workdesc.get_h()/fh));
315 workdesc.clear_flags();
316 workdesc.set_wh(tmpw,tmph);
317 //synfig::info("fw: %d, fh: %d",fw,fh);
319 //render the blur fodder
320 if(!context.accelerated_render(&worksurface,quality,workdesc,&stageone))
323 //render the background
324 if(!context.accelerated_render(surface,quality,renddesc,&stageone))
327 // Copy over the alpha
328 blurred.set_wh(worksurface.get_w(),worksurface.get_h());
329 for(int j=0;j<worksurface.get_h();j++)
330 for(int i=0;i<worksurface.get_w();i++)
331 blurred[j][i]=worksurface[j][i].get_a();
334 Blur(size,type,&stagetwo)(blurred,workdesc.get_br()-workdesc.get_tl(),blurred);
337 int u = halfsizex-(offset_u<0?offset_u:0), v = halfsizey-(offset_v<0?offset_v:0);
338 for(y=0;y<renddesc.get_h();y++,v++)
340 u = halfsizex-(offset_u<0?offset_u:0);
341 for(x=0;x<renddesc.get_w();x++,u++)
346 a.set_a(blurred.linear_sample(((float)offset_u+(float)u)/(float)fw,((float)offset_v+(float)v)/(float)fh));
348 a.set_a(1.0f-blurred.linear_sample(((float)offset_u+(float)u)/fw,((float)offset_v+(float)v)/(float)fh));
350 if(a.get_a() || get_blend_method()==Color::BLEND_STRAIGHT)
352 (*surface)[y][x]=Color::blend(a,(*surface)[y][x],get_amount(),get_blend_method());
359 if(cb && !cb->amount_complete(10000,10000))
361 //if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
369 Layer_Shade::get_param_vocab(void)const
371 Layer::Vocab ret(Layer_Composite::get_param_vocab());
373 ret.push_back(ParamDesc("color")
374 .set_local_name(_("Color"))
376 ret.push_back(ParamDesc("offset")
377 .set_local_name(_("Offset"))
379 ret.push_back(ParamDesc("size")
380 .set_local_name(_("Size"))
381 .set_description(_("Size of Shade"))
383 .set_origin("offset")
385 ret.push_back(ParamDesc("type")
386 .set_local_name(_("Type"))
387 .set_description(_("Type of blur to use"))
389 .add_enum_value(Blur::BOX,"box",_("Box Blur"))
390 .add_enum_value(Blur::FASTGAUSSIAN,"fastgaussian",_("Fast Gaussian Blur"))
391 .add_enum_value(Blur::CROSS,"cross",_("Cross-Hatch Blur"))
392 .add_enum_value(Blur::GAUSSIAN,"gaussian",_("Gaussian Blur"))
393 .add_enum_value(Blur::DISC,"disc",_("Disc Blur"))
396 ret.push_back(ParamDesc("invert")
397 .set_local_name(_("Invert"))
404 Layer_Shade::get_full_bounding_rect(Context context)const
407 return context.get_full_bounding_rect();
410 return Rect::full_plane();
412 Rect under(context.get_full_bounding_rect());
414 if(Color::is_onto(get_blend_method()))
417 Rect bounds((under+offset).expand_x(size[0]).expand_y(size[1]));