Merge branch 'genete_static_values'
[synfig.git] / synfig-core / src / modules / lyr_std / julia.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file julia.cpp
3 **      \brief Implementation of the "Julia Set" layer
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **      Copyright (c) 2007 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 ** === N O T E S ===========================================================
23 **
24 ** ========================================================================= */
25
26 /* === H E A D E R S ======================================================= */
27
28 #ifdef USING_PCH
29 #       include "pch.h"
30 #else
31 #ifdef HAVE_CONFIG_H
32 #       include <config.h>
33 #endif
34
35 #include "julia.h"
36
37 #include <synfig/string.h>
38 #include <synfig/time.h>
39 #include <synfig/context.h>
40 #include <synfig/paramdesc.h>
41 #include <synfig/renddesc.h>
42 #include <synfig/surface.h>
43 #include <synfig/value.h>
44 #include <synfig/valuenode.h>
45
46 #endif
47
48 /* === M A C R O S ========================================================= */
49
50 #define LOG_OF_2                0.69314718055994528623
51
52 /* === G L O B A L S ======================================================= */
53
54 SYNFIG_LAYER_INIT(Julia);
55 SYNFIG_LAYER_SET_NAME(Julia,"julia");
56 SYNFIG_LAYER_SET_LOCAL_NAME(Julia,N_("Julia Set"));
57 SYNFIG_LAYER_SET_CATEGORY(Julia,N_("Fractals"));
58 SYNFIG_LAYER_SET_VERSION(Julia,"0.1");
59 SYNFIG_LAYER_SET_CVS_ID(Julia,"$Id$");
60
61 /* === P R O C E D U R E S ================================================= */
62
63 inline void
64 color_neg_flip(Color &color)
65 {
66         if(color.get_a()==0)
67         {
68                 color=Color::alpha();
69                 return;
70         }
71
72         if(color.get_a()<0)
73                 color=-color;
74
75         if(color.get_r()<0)
76         {
77                 color.set_g(color.get_g()-color.get_r());
78                 color.set_b(color.get_b()-color.get_r());
79                 color.set_r(0);
80         }
81         if(color.get_g()<0)
82         {
83                 color.set_r(color.get_r()-color.get_g());
84                 color.set_b(color.get_b()-color.get_g());
85                 color.set_g(0);
86         }
87         if(color.get_b()<0)
88         {
89                 color.set_r(color.get_r()-color.get_b());
90                 color.set_g(color.get_g()-color.get_b());
91                 color.set_b(0);
92         }
93 }
94
95 /* === M E T H O D S ======================================================= */
96
97 Julia::Julia():color_shift(angle::degrees(0))
98 {
99         icolor=Color::black();
100         ocolor=Color::black();
101         iterations=32;
102         color_shift=Angle::deg(0);
103
104         distort_inside=true;
105         distort_outside=true;
106         shade_inside=true;
107         shade_outside=true;
108         solid_inside=false;
109         solid_outside=false;
110         invert_inside=false;
111         invert_outside=false;
112         color_inside=true;
113         color_outside=false;
114         color_cycle=false;
115         smooth_outside=true;
116         broken=false;
117         seed=Point(0,0);
118
119         bailout=4;
120         lp=log(log(bailout));
121         Layer::Vocab voc(get_param_vocab());
122         Layer::fill_static(voc);
123 }
124
125 bool
126 Julia::set_param(const String & param, const ValueBase &value)
127 {
128
129         IMPORT(icolor);
130         IMPORT(ocolor);
131         IMPORT(color_shift);
132         IMPORT(seed);
133
134         IMPORT(distort_inside);
135         IMPORT(distort_outside);
136         IMPORT(shade_inside);
137         IMPORT(shade_outside);
138         IMPORT(solid_inside);
139         IMPORT(solid_outside);
140         IMPORT(invert_inside);
141         IMPORT(invert_outside);
142         IMPORT(color_inside);
143         IMPORT(color_outside);
144
145         IMPORT(color_cycle);
146         IMPORT(smooth_outside);
147         IMPORT(broken);
148
149 // TODO: Use IMPORT_PLUS
150         if(param=="iterations" && value.same_type_as(iterations))
151         {
152                 iterations=value.get(iterations);
153                 if(iterations<0)
154                         iterations=0;
155                 if(iterations>500000)
156                         iterations=500000;
157                 set_param_static(param, value.get_static());
158                 return true;
159         }
160         if(param=="bailout" && value.same_type_as(bailout))
161         {
162                 bailout=value.get(bailout);
163                 bailout*=bailout;
164                 lp=log(log(bailout));
165                 set_param_static(param, value.get_static());
166                 return true;
167         }
168
169         return false;
170 }
171
172 ValueBase
173 Julia::get_param(const String & param)const
174 {
175         EXPORT(icolor);
176         EXPORT(ocolor);
177         EXPORT(color_shift);
178         EXPORT(iterations);
179         EXPORT(seed);
180
181         EXPORT(distort_inside);
182         EXPORT(distort_outside);
183         EXPORT(shade_inside);
184         EXPORT(shade_outside);
185         EXPORT(solid_inside);
186         EXPORT(solid_outside);
187         EXPORT(invert_inside);
188         EXPORT(invert_outside);
189         EXPORT(color_inside);
190         EXPORT(color_outside);
191         EXPORT(color_cycle);
192         EXPORT(smooth_outside);
193         EXPORT(broken);
194
195         if(param=="bailout")
196         {
197                 ValueBase ret(sqrt(bailout));
198                 ret.set_static(get_param_static(param));
199                 return ret;
200         }
201
202         EXPORT_NAME();
203         EXPORT_VERSION();
204
205         return ValueBase();
206 }
207
208 Color
209 Julia::get_color(Context context, const Point &pos)const
210 {
211         Real
212                 cr, ci,
213                 zr, zi,
214                 zr_hold;
215
216         ColorReal
217                 depth, mag(0);
218
219         Color
220                 ret;
221
222         cr=seed[0];
223         ci=seed[1];
224         zr=pos[0];
225         zi=pos[1];
226
227         for(int i=0;i<iterations;i++)
228         {
229                 // Perform complex multiplication
230                 zr_hold=zr;
231                 zr=zr*zr-zi*zi + cr;
232                 zi=zr_hold*zi*2 + ci;
233
234                 // Use "broken" algorithm, if requested (looks weird)
235                 if(broken)zr+=zi;
236
237                 // Calculate Magnitude
238                 mag=zr*zr+zi*zi;
239
240                 if(mag>4)
241                 {
242                         if(smooth_outside)
243                         {
244                                 // Darco's original mandelbrot smoothing algo
245                                 // depth=((Point::value_type)i+(2.0-sqrt(mag))/PI);
246
247                                 // Linas Vepstas algo (Better than darco's)
248                                 // See (http://linas.org/art-gallery/escape/smooth.html)
249                                 depth= (ColorReal)i - log(log(sqrt(mag))) / LOG_OF_2;
250
251                                 // Clamp
252                                 if(depth<0) depth=0;
253                         }
254                         else
255                                 depth=static_cast<ColorReal>(i);
256
257                         if(solid_outside)
258                                 ret=ocolor;
259                         else
260                                 if(distort_outside)
261                                         ret=context.get_color(Point(zr,zi));
262                                 else
263                                         ret=context.get_color(pos);
264
265                         if(invert_outside)
266                                 ret=~ret;
267
268                         if(color_outside)
269                                 ret=ret.set_uv(zr,zi).clamped_negative();
270
271                         if(color_cycle)
272                                 ret=ret.rotate_uv(color_shift.operator*(depth)).clamped_negative();
273
274                         if(shade_outside)
275                         {
276                                 ColorReal alpha=depth/static_cast<ColorReal>(iterations);
277                                 ret=(ocolor-ret)*alpha+ret;
278                         }
279                         return ret;
280                 }
281         }
282
283         if(solid_inside)
284                 ret=icolor;
285         else
286                 if(distort_inside)
287                         ret=context.get_color(Point(zr,zi));
288                 else
289                         ret=context.get_color(pos);
290
291         if(invert_inside)
292                 ret=~ret;
293
294         if(color_inside)
295                 ret=ret.set_uv(zr,zi).clamped_negative();
296
297         if(shade_inside)
298                 ret=(icolor-ret)*mag+ret;
299
300         return ret;
301 }
302
303 Layer::Vocab
304 Julia::get_param_vocab()const
305 {
306         Layer::Vocab ret;
307
308         ret.push_back(ParamDesc("icolor")
309                 .set_local_name(_("Inside Color"))
310                 .set_description(_("Color of the Set"))
311         );
312         ret.push_back(ParamDesc("ocolor")
313                 .set_local_name(_("Outside Color"))
314                 .set_description(_("Color outside the Set"))
315         );
316         ret.push_back(ParamDesc("color_shift")
317                 .set_local_name(_("Color Shift"))
318         );
319         ret.push_back(ParamDesc("iterations")
320                 .set_local_name(_("Iterations"))
321         );
322         ret.push_back(ParamDesc("seed")
323                 .set_local_name(_("Seed Point"))
324         );
325         ret.push_back(ParamDesc("bailout")
326                 .set_local_name(_("Bailout ValueBase"))
327         );
328
329         ret.push_back(ParamDesc("distort_inside")
330                 .set_local_name(_("Distort Inside"))
331         );
332         ret.push_back(ParamDesc("shade_inside")
333                 .set_local_name(_("Shade Inside"))
334         );
335         ret.push_back(ParamDesc("solid_inside")
336                 .set_local_name(_("Solid Inside"))
337         );
338         ret.push_back(ParamDesc("invert_inside")
339                 .set_local_name(_("Invert Inside"))
340         );
341         ret.push_back(ParamDesc("color_inside")
342                 .set_local_name(_("Color Inside"))
343         );
344         ret.push_back(ParamDesc("distort_outside")
345                 .set_local_name(_("Distort Outside"))
346         );
347         ret.push_back(ParamDesc("shade_outside")
348                 .set_local_name(_("Shade Outside"))
349         );
350         ret.push_back(ParamDesc("solid_outside")
351                 .set_local_name(_("Solid Outside"))
352         );
353         ret.push_back(ParamDesc("invert_outside")
354                 .set_local_name(_("Invert Outside"))
355         );
356         ret.push_back(ParamDesc("color_outside")
357                 .set_local_name(_("Color Outside"))
358         );
359
360         ret.push_back(ParamDesc("color_cycle")
361                 .set_local_name(_("Color Cycle"))
362         );
363         ret.push_back(ParamDesc("smooth_outside")
364                 .set_local_name(_("Smooth Outside"))
365                 .set_description(_("Smooth the coloration outside the set"))
366         );
367         ret.push_back(ParamDesc("broken")
368                 .set_local_name(_("Break Set"))
369                 .set_description(_("Modify equation to achieve interesting results"))
370         );
371
372
373         return ret;
374 }