marked stable
[synfig.git] / synfig-core / tags / stable / src / modules / mod_noise / noise.cpp
1 /* === S I N F G =========================================================== */
2 /*!     \file noise.cpp
3 **      \brief blehh
4 **
5 **      $Id: noise.cpp,v 1.2 2005/01/13 06:48:39 darco Exp $
6 **
7 **      \legal
8 **      Copyright (c) 2002 Robert B. Quattlebaum Jr.
9 **
10 **      This software and associated documentation
11 **      are CONFIDENTIAL and PROPRIETARY property of
12 **      the above-mentioned copyright holder.
13 **
14 **      You may not copy, print, publish, or in any
15 **      other way distribute this software without
16 **      a prior written agreement with
17 **      the copyright holder.
18 **      \endlegal
19 */
20 /* ========================================================================= */
21
22 /* === H E A D E R S ======================================================= */
23
24 #ifdef USING_PCH
25 #       include "pch.h"
26 #else
27 #ifdef HAVE_CONFIG_H
28 #       include <config.h>
29 #endif
30
31 #include "noise.h"
32
33 #include <sinfg/string.h>
34 #include <sinfg/time.h>
35 #include <sinfg/context.h>
36 #include <sinfg/paramdesc.h>
37 #include <sinfg/renddesc.h>
38 #include <sinfg/surface.h>
39 #include <sinfg/value.h>
40 #include <sinfg/valuenode.h>
41
42 #endif
43
44 /* === M A C R O S ========================================================= */
45
46 using namespace sinfg;
47 using namespace std;
48 using namespace etl;
49
50 /* === G L O B A L S ======================================================= */
51
52 SINFG_LAYER_INIT(Noise);
53 SINFG_LAYER_SET_NAME(Noise,"noise");
54 SINFG_LAYER_SET_LOCAL_NAME(Noise,_("Noise Gradient"));
55 SINFG_LAYER_SET_CATEGORY(Noise,_("Gradients"));
56 SINFG_LAYER_SET_VERSION(Noise,"0.0");
57 SINFG_LAYER_SET_CVS_ID(Noise,"$Id: noise.cpp,v 1.2 2005/01/13 06:48:39 darco Exp $");
58
59 /* === P R O C E D U R E S ================================================= */
60
61 /* === M E T H O D S ======================================================= */
62
63 Noise::Noise():
64         size(1,1),
65         gradient(Color::black(), Color::white())
66 {
67         smooth=2;
68         detail=4;
69         speed=0;
70         do_alpha=false;
71         random.set_seed(time(NULL));
72         turbulent=false;
73         displacement=Vector(1,1);
74         do_displacement=false;
75         super_sample=false;
76 }
77
78
79
80 inline Color
81 Noise::color_func(const Point &point, float pixel_size,Context context)const
82 {
83         Color ret(0,0,0,0);
84         
85         float x(point[0]/size[0]*(1<<detail));
86         float y(point[1]/size[1]*(1<<detail));
87         float x2(0),y2(0);
88         
89         if(super_sample&&pixel_size)
90         {
91                 x2=(point[0]+pixel_size)/size[0]*(1<<detail);
92                 y2=(point[1]+pixel_size)/size[1]*(1<<detail);
93         }
94         
95         int i;
96         Time time;
97         time=speed*curr_time;
98         int smooth((!speed && Noise::smooth==3)?5:Noise::smooth);
99         
100         float t(time);
101
102         {
103                 float amount=0.0f;
104                 float amount2=0.0f;
105                 float amount3=0.0f;
106                 float alpha=0.0f;
107                 for(i=0;i<detail;i++)
108                 {
109                         amount=random(smooth,0+(detail-i)*5,x,y,t)+amount*0.5;
110                         if(amount<-1)amount=-1;if(amount>1)amount=1;
111                         
112                         if(super_sample&&pixel_size)
113                         {
114                                 amount2=random(smooth,0+(detail-i)*5,x2,y,t)+amount2*0.5;
115                                 if(amount2<-1)amount2=-1;if(amount2>1)amount2=1;
116
117                                 amount3=random(smooth,0+(detail-i)*5,x,y2,t)+amount3*0.5;
118                                 if(amount3<-1)amount3=-1;if(amount3>1)amount3=1;
119
120                                 if(turbulent)
121                                 {
122                                         amount2=abs(amount2);
123                                         amount3=abs(amount3);
124                                 }
125
126                                 x2*=0.5f;
127                                 y2*=0.5f;
128                         }
129                         
130                         if(do_alpha)
131                         {
132                                 alpha=random(smooth,3+(detail-i)*5,x,y,t)+alpha*0.5;
133                                 if(alpha<-1)alpha=-1;if(alpha>1)alpha=1;
134                         }
135                         
136                         if(turbulent)
137                         {
138                                 amount=abs(amount);
139                                 alpha=abs(alpha);
140                         }
141                                 
142                         x*=0.5f;
143                         y*=0.5f;
144                         //t*=0.5f;
145                 }
146
147                 if(!turbulent)
148                 {
149                         amount=amount/2.0f+0.5f;
150                         alpha=alpha/2.0f+0.5f;
151
152                         if(super_sample&&pixel_size)
153                         {
154                                 amount2=amount2/2.0f+0.5f;
155                                 amount3=amount3/2.0f+0.5f;
156                         }
157                 }
158                 
159                 if(super_sample && pixel_size)
160                         ret=gradient(amount,max(amount3,max(amount,amount2))-min(amount3,min(amount,amount2)));
161                 else
162                         ret=gradient(amount);
163
164                 if(do_alpha)
165                         ret.set_a(ret.get_a()*(alpha));
166         }
167         return ret;
168 }
169
170 inline float
171 Noise::calc_supersample(const sinfg::Point &x, float pw,float ph)const
172 {
173         return 0.0f;
174 }
175
176 void
177 Noise::set_time(sinfg::Context context, sinfg::Time t)const
178 {
179         curr_time=t;
180         context.set_time(t);
181 }
182
183 void
184 Noise::set_time(sinfg::Context context, sinfg::Time t, const sinfg::Point &point)const
185 {
186         curr_time=t;
187         context.set_time(t,point);
188 }
189
190 sinfg::Layer::Handle
191 Noise::hit_check(sinfg::Context context, const sinfg::Point &point)const
192 {
193         if(get_blend_method()==Color::BLEND_STRAIGHT && get_amount()>=0.5)
194                 return const_cast<Noise*>(this);
195         if(get_amount()==0.0)
196                 return context.hit_check(point);
197         if(color_func(point,0,context).get_a()>0.5)
198                 return const_cast<Noise*>(this);
199         return false;
200 }
201
202 bool
203 Noise::set_param(const String & param, const ValueBase &value)
204 {
205         if(param=="seed" && value.same_as(int()))
206         {
207                 random.set_seed(value.get(int()));
208                 return true;
209         }
210         IMPORT(size);
211         IMPORT(speed);
212         IMPORT(smooth);
213         IMPORT(detail);
214         IMPORT(do_alpha);
215         IMPORT(gradient);
216         IMPORT(turbulent);
217         IMPORT(super_sample);
218         
219         return Layer_Composite::set_param(param,value); 
220 }
221
222 ValueBase
223 Noise::get_param(const String & param)const
224 {
225         if(param=="seed")
226                 return random.get_seed();
227         EXPORT(size);
228         EXPORT(speed);
229         EXPORT(smooth);
230         EXPORT(detail);
231         EXPORT(do_alpha);
232         EXPORT(gradient);
233         EXPORT(turbulent)       
234         EXPORT(super_sample);
235         
236         EXPORT_NAME();
237         EXPORT_VERSION();
238                 
239         return Layer_Composite::get_param(param);       
240 }
241
242 Layer::Vocab
243 Noise::get_param_vocab()const
244 {
245         Layer::Vocab ret(Layer_Composite::get_param_vocab());
246         
247         ret.push_back(ParamDesc("gradient")
248                 .set_local_name(_("Gradient"))
249         );
250         ret.push_back(ParamDesc("seed")
251                 .set_local_name(_("Random Seed"))
252         );
253         ret.push_back(ParamDesc("size")
254                 .set_local_name(_("Size"))
255         );
256         ret.push_back(ParamDesc("smooth")
257                 .set_local_name(_("Interpolation"))
258                 .set_description(_("What type of interpolation to use"))
259                 .set_hint("enum")
260                 .add_enum_value(0,"nearest",_("Nearest Neighbor"))
261                 .add_enum_value(1,"linear",_("Linear"))
262                 .add_enum_value(2,"cosine",_("Cosine"))
263                 .add_enum_value(3,"spline",_("Spline"))
264                 .add_enum_value(4,"cubic",_("Cubic"))
265         );
266         ret.push_back(ParamDesc("detail")
267                 .set_local_name(_("Detail"))
268         );
269         ret.push_back(ParamDesc("speed")
270                 .set_local_name(_("Animation Speed"))
271         );
272         ret.push_back(ParamDesc("turbulent")
273                 .set_local_name(_("Turbulent"))
274         );
275         ret.push_back(ParamDesc("do_alpha")
276                 .set_local_name(_("Do Alpha"))
277         );
278         ret.push_back(ParamDesc("super_sample")
279                 .set_local_name(_("Super Sampling"))
280         );
281         
282         return ret;
283 }
284
285 Color
286 Noise::get_color(Context context, const Point &point)const
287 {
288         const Color color(color_func(point,0,context));
289
290         if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
291                 return color;
292         else
293                 return Color::blend(color,context.get_color(point),get_amount(),get_blend_method());
294 }
295
296 bool
297 Noise::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
298 {
299         SuperCallback supercb(cb,0,9500,10000);
300
301         if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
302         {
303                 surface->set_wh(renddesc.get_w(),renddesc.get_h());
304         }
305         else
306         {
307                 if(!context.accelerated_render(surface,quality,renddesc,&supercb))
308                         return false;
309                 if(get_amount()==0)
310                         return true;
311         }
312
313                 
314         int x,y;
315
316         Surface::pen pen(surface->begin());
317         const Real pw(renddesc.get_pw()),ph(renddesc.get_ph());
318         Point pos;
319         Point tl(renddesc.get_tl());
320         const int w(surface->get_w());
321         const int h(surface->get_h());
322         float supersampleradius((abs(pw)+abs(ph))*0.5f);
323         if(quality>=8)
324                 supersampleradius=0;
325         
326         if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
327         {
328                 for(y=0,pos[1]=tl[1];y<h;y++,pen.inc_y(),pen.dec_x(x),pos[1]+=ph)
329                         for(x=0,pos[0]=tl[0];x<w;x++,pen.inc_x(),pos[0]+=pw)
330                                 pen.put_value(color_func(pos,supersampleradius,context));
331         }
332         else
333         {
334                 for(y=0,pos[1]=tl[1];y<h;y++,pen.inc_y(),pen.dec_x(x),pos[1]+=ph)
335                         for(x=0,pos[0]=tl[0];x<w;x++,pen.inc_x(),pos[0]+=pw)
336                                 pen.put_value(Color::blend(color_func(pos,supersampleradius,context),pen.get_value(),get_amount(),get_blend_method()));
337         }
338
339         // Mark our progress as finished
340         if(cb && !cb->amount_complete(10000,10000))
341                 return false;
342
343         return true;
344 }