c0e27ea42884c707c62627988611e6a997f54d41
[synfig.git] / synfig-core / src / synfig / layer_motionblur.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file layer_motionblur.cpp
3 **      \brief Implementation of the "Motion Blur" layer
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **      Copyright (c) 2007, 2008 Chris Moore
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 "string.h"
34 #include "layer_motionblur.h"
35 #include "time.h"
36 #include "context.h"
37 #include "paramdesc.h"
38 #include "renddesc.h"
39 #include "surface.h"
40 #include "value.h"
41 #include "valuenode.h"
42 #include "canvas.h"
43
44 #endif
45
46 /* === U S I N G =========================================================== */
47
48 using namespace synfig;
49 using namespace etl;
50 using namespace std;
51
52 /* === G L O B A L S ======================================================= */
53
54 SYNFIG_LAYER_INIT(Layer_MotionBlur);
55 SYNFIG_LAYER_SET_NAME(Layer_MotionBlur,"MotionBlur"); // todo: use motion_blur
56 SYNFIG_LAYER_SET_LOCAL_NAME(Layer_MotionBlur,N_("Motion Blur"));
57 SYNFIG_LAYER_SET_CATEGORY(Layer_MotionBlur,N_("Blurs"));
58 SYNFIG_LAYER_SET_VERSION(Layer_MotionBlur,"0.1");
59 SYNFIG_LAYER_SET_CVS_ID(Layer_MotionBlur,"$Id$");
60
61 /* === M E M B E R S ======================================================= */
62
63 Layer_MotionBlur::Layer_MotionBlur():
64         Layer_Composite         (1.0,Color::BLEND_STRAIGHT),
65         aperture                        (0),
66         subsamples_factor       (1.0),
67         subsampling_type        (SUBSAMPLING_HYPERBOLIC),
68         subsample_start         (0.0),
69         subsample_end           (1.0),
70         aperture_static                         (false),
71         subsamples_factor_static        (false),
72         subsampling_type_static         (true),
73         subsample_start_static          (false),
74         subsample_end_static            (false)
75 {
76 }
77
78 bool
79 Layer_MotionBlur::set_param(const String &param, const ValueBase &value)
80 {
81
82         IMPORT(aperture);
83         IMPORT(subsamples_factor);
84         IMPORT(subsampling_type);
85         IMPORT(subsample_start);
86         IMPORT(subsample_end);
87         return Layer_Composite::set_param(param,value);
88 }
89
90 ValueBase
91 Layer_MotionBlur::get_param(const String &param)const
92 {
93         EXPORT(aperture);
94         EXPORT(subsamples_factor);
95         EXPORT(subsampling_type);
96         EXPORT(subsample_start);
97         EXPORT(subsample_end);
98
99         EXPORT_NAME();
100         EXPORT_VERSION();
101
102         return Layer_Composite::get_param(param);
103 }
104
105 void
106 Layer_MotionBlur::set_time(Context context, Time time)const
107 {
108         context.set_time(time);
109         time_cur=time;
110 }
111
112 void
113 Layer_MotionBlur::set_time(Context context, Time time, const Point &pos)const
114 {
115         context.set_time(time,pos);
116         time_cur=time;
117 }
118
119 Color
120 Layer_MotionBlur::get_color(Context context, const Point &pos)const
121 {
122 /*      if(aperture)
123         {
124                 Time time(time_cur);
125                 time+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) *aperture -aperture*0.5;
126                 context.set_time(time, pos);
127         }
128 */
129         return context.get_color(pos);
130 }
131
132 Layer::Vocab
133 Layer_MotionBlur::get_param_vocab()const
134 {
135         Layer::Vocab ret;
136         //ret=Layer_Composite::get_param_vocab();
137
138         ret.push_back(ParamDesc("aperture")
139                 .set_local_name(_("Aperture"))
140                 .set_description(_("Shutter Time"))
141         );
142
143         ret.push_back(ParamDesc("subsamples_factor")
144                 .set_local_name(_("Subsamples Factor"))
145                 .set_description(_("Multiplies The Number Of Subsamples Rendered"))
146         );
147
148         ret.push_back(ParamDesc("subsampling_type")
149                 .set_local_name(_("Subsampling Type"))
150                 .set_description(_("Curve Type For Weighting Subsamples"))
151                 .set_hint("enum")
152                 .add_enum_value(SUBSAMPLING_CONSTANT,"constant",_("Constant"))
153                 .add_enum_value(SUBSAMPLING_LINEAR,"linear",_("Linear"))
154                 .add_enum_value(SUBSAMPLING_HYPERBOLIC,"hyperbolic",_("Hyperbolic"))
155         );
156
157         ret.push_back(ParamDesc("subsample_start")
158                 .set_local_name(_("Subsample Start Amount"))
159                 .set_description(_("Relative Amount Of The First Subsample, For Linear Weighting"))
160         );
161
162         ret.push_back(ParamDesc("subsample_end")
163                 .set_local_name(_("Subsample End Amount"))
164                 .set_description(_("Relative Amount Of The Last Subsample, For Linear Weighting"))
165         );
166
167         return ret;
168 }
169
170 bool
171 Layer_MotionBlur::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
172 {
173         if(aperture && quality<=10)
174         {
175                 //int x, y;
176                 SuperCallback subimagecb;
177                 int samples=1;
178                 switch(quality)
179                 {
180                         case 1: // Production Quality
181                                 samples=32;
182                                 break;
183                         case 2: // Excellent Quality
184                                 samples=24;
185                                 break;
186                         case 3: // Good Quality
187                                 samples=16;
188                                 break;
189                         case 4: // Moderate Quality
190                                 samples=12;
191                                 break;
192                         case 5: // Draft Quality
193                                 samples=7;
194                                 break;
195                         case 6:
196                                 samples=6;
197                                 break;
198                         case 7:
199                                 samples=5;
200                                 break;
201                         case 8:
202                                 samples=3;
203                                 break;
204                         case 9:
205                                 samples=2;
206                                 break;
207                         case 10: // Rough Quality
208             default:
209                                 samples=1;
210                                 break;
211
212                 }
213
214                 samples *= subsamples_factor;
215
216                 if (samples <= 1) return context.accelerated_render(surface,quality,renddesc,cb);
217
218                 // Only in modes where subsample_start/end matters...
219                 if(subsampling_type == SUBSAMPLING_LINEAR)
220                 {
221                         // We won't render when the scale==0, so we'll use those samples elsewhere
222                         if(subsample_start == 0) samples++;
223                         if(subsample_end == 0) samples++;
224                 }
225
226                 Surface tmp;
227                 int i;
228                 float scale, divisor = 0;
229
230                 surface->set_wh(renddesc.get_w(),renddesc.get_h());
231                 surface->clear();
232
233                 // Render subsamples from time_cur-aperture to time_cur
234                 for(i=0;i<samples;i++)
235                 {
236                         float pos = i/(samples-1.0);
237                         float ipos = 1.0-pos;
238                         switch(subsampling_type)
239                         {
240                                 case SUBSAMPLING_LINEAR:
241                                         scale = ipos*subsample_start + pos*subsample_end;
242                                         break;
243                                 case SUBSAMPLING_HYPERBOLIC:
244                                         scale = 1.0/(samples-i);
245                                         break;
246                                 case SUBSAMPLING_CONSTANT:
247                                 default:
248                                         scale = 1.0; // Weights don't matter for constant overall subsampling.
249                                         break;
250                         }
251                         // Don't bother rendering if scale is zero
252                         if(scale==0)
253                                 continue;
254                         divisor += scale;
255                         subimagecb=SuperCallback(cb,i*(5000/samples),(i+1)*(5000/samples),5000);
256                         context.set_time(time_cur-aperture*ipos);
257                         if(!context.accelerated_render(&tmp,quality,renddesc,&subimagecb))
258                                 return false;
259                         for(int y=0;y<renddesc.get_h();y++)
260                                 for(int x=0;x<renddesc.get_w();x++)
261                                         (*surface)[y][x]+=tmp[y][x].premult_alpha()*scale;
262                 }
263                 for(int y=0;y<renddesc.get_h();y++)
264                         for(int x=0;x<renddesc.get_w();x++)
265                                 (*surface)[y][x]=((*surface)[y][x]/divisor).demult_alpha();
266         }
267         else
268                 return context.accelerated_render(surface,quality,renddesc,cb);
269
270         return true;
271 }
272
273
274 bool
275 Layer_MotionBlur::set_param_static(const String &param, const bool x)
276 {
277         SET_STATIC(aperture, x)
278         SET_STATIC(subsamples_factor, x)
279         SET_STATIC(subsampling_type, x)
280         SET_STATIC(subsample_start, x)
281         SET_STATIC(subsample_end, x)
282
283         return Layer_Composite::set_param_static(param, x);
284 }
285
286
287 bool
288 Layer_MotionBlur::get_param_static(const String &param) const
289 {
290
291         GET_STATIC(aperture)
292         GET_STATIC(subsamples_factor)
293         GET_STATIC(subsampling_type)
294         GET_STATIC(subsample_start)
295         GET_STATIC(subsample_end)
296
297         return Layer_Composite::get_param_static(param);
298 }