Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-core / tags / synfig_0_61_07_rc3 / src / modules / lyr_std / julia.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file julia.cpp
3 **      \brief Template Header
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,_("Julia Set"));
57 SYNFIG_LAYER_SET_CATEGORY(Julia,_("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 }
122
123 bool
124 Julia::set_param(const String & param, const ValueBase &value)
125 {
126
127         IMPORT(icolor);
128         IMPORT(ocolor);
129         IMPORT(color_shift);
130         IMPORT(seed);
131
132         IMPORT(distort_inside);
133         IMPORT(distort_outside);
134         IMPORT(shade_inside);
135         IMPORT(shade_outside);
136         IMPORT(solid_inside);
137         IMPORT(solid_outside);
138         IMPORT(invert_inside);
139         IMPORT(invert_outside);
140         IMPORT(color_inside);
141         IMPORT(color_outside);
142
143         IMPORT(color_cycle);
144         IMPORT(smooth_outside);
145         IMPORT(broken);
146
147         if(param=="iterations" && value.same_type_as(iterations))
148         {
149                 iterations=value.get(iterations);
150                 if(iterations<0)
151                         iterations=0;
152                 if(iterations>500000)
153                         iterations=500000;
154                 return true;
155         }
156         if(param=="bailout" && value.same_type_as(bailout))
157         {
158                 bailout=value.get(bailout);
159                 bailout*=bailout;
160                 lp=log(log(bailout));
161                 return true;
162         }
163
164         return false;
165 }
166
167 ValueBase
168 Julia::get_param(const String & param)const
169 {
170         EXPORT(icolor);
171         EXPORT(ocolor);
172         EXPORT(color_shift);
173         EXPORT(iterations);
174         EXPORT(seed);
175
176         EXPORT(distort_inside);
177         EXPORT(distort_outside);
178         EXPORT(shade_inside);
179         EXPORT(shade_outside);
180         EXPORT(solid_inside);
181         EXPORT(solid_outside);
182         EXPORT(invert_inside);
183         EXPORT(invert_outside);
184         EXPORT(color_inside);
185         EXPORT(color_outside);
186         EXPORT(color_cycle);
187         EXPORT(smooth_outside);
188         EXPORT(broken);
189
190         if(param=="bailout")
191                 return sqrt(bailout);
192
193         EXPORT_NAME();
194         EXPORT_VERSION();
195
196         return ValueBase();
197 }
198
199 Color
200 Julia::get_color(Context context, const Point &pos)const
201 {
202         Real
203                 cr, ci,
204                 zr, zi,
205                 zr_hold;
206
207         ColorReal
208                 depth, mag(0);
209
210         Color
211                 ret;
212
213         cr=seed[0];
214         ci=seed[1];
215         zr=pos[0];
216         zi=pos[1];
217
218         for(int i=0;i<iterations;i++)
219         {
220                 // Perform complex multiplication
221                 zr_hold=zr;
222                 zr=zr*zr-zi*zi + cr;
223                 zi=zr_hold*zi*2 + ci;
224
225                 // Use "broken" algorithm, if requested (looks weird)
226                 if(broken)zr+=zi;
227
228                 // Calculate Magnitude
229                 mag=zr*zr+zi*zi;
230
231                 if(mag>4)
232                 {
233                         if(smooth_outside)
234                         {
235                                 // Darco's original mandelbrot smoothing algo
236                                 // depth=((Point::value_type)i+(2.0-sqrt(mag))/PI);
237
238                                 // Linas Vepstas algo (Better than darco's)
239                                 // See (http://linas.org/art-gallery/escape/smooth.html)
240                                 depth= (ColorReal)i - log(log(sqrt(mag))) / LOG_OF_2;
241
242                                 // Clamp
243                                 if(depth<0) depth=0;
244                         }
245                         else
246                                 depth=static_cast<ColorReal>(i);
247
248                         if(solid_outside)
249                                 ret=ocolor;
250                         else
251                                 if(distort_outside)
252                                         ret=context.get_color(Point(zr,zi));
253                                 else
254                                         ret=context.get_color(pos);
255
256                         if(invert_outside)
257                                 ret=~ret;
258
259                         if(color_outside)
260                                 ret=ret.set_uv(zr,zi).clamped_negative();
261
262                         if(color_cycle)
263                                 ret=ret.rotate_uv(color_shift.operator*(depth)).clamped_negative();
264
265                         if(shade_outside)
266                         {
267                                 ColorReal alpha=depth/static_cast<ColorReal>(iterations);
268                                 ret=(ocolor-ret)*alpha+ret;
269                         }
270                         return ret;
271                 }
272         }
273
274         if(solid_inside)
275                 ret=icolor;
276         else
277                 if(distort_inside)
278                         ret=context.get_color(Point(zr,zi));
279                 else
280                         ret=context.get_color(pos);
281
282         if(invert_inside)
283                 ret=~ret;
284
285         if(color_inside)
286                 ret=ret.set_uv(zr,zi).clamped_negative();
287
288         if(shade_inside)
289                 ret=(icolor-ret)*mag+ret;
290
291         return ret;
292 }
293
294 Layer::Vocab
295 Julia::get_param_vocab()const
296 {
297         Layer::Vocab ret;
298
299         ret.push_back(ParamDesc("icolor")
300                 .set_local_name(_("Inside Color"))
301                 .set_description(_("Color of the Set"))
302         );
303         ret.push_back(ParamDesc("ocolor")
304                 .set_local_name(_("Outside Color"))
305                 .set_description(_("Color outside the Set"))
306         );
307         ret.push_back(ParamDesc("color_shift")
308                 .set_local_name(_("Color Shift"))
309         );
310         ret.push_back(ParamDesc("iterations")
311                 .set_local_name(_("Iterations"))
312         );
313         ret.push_back(ParamDesc("seed")
314                 .set_local_name(_("Seed Point"))
315         );
316         ret.push_back(ParamDesc("bailout")
317                 .set_local_name(_("Bailout ValueBase"))
318         );
319
320         ret.push_back(ParamDesc("distort_inside")
321                 .set_local_name(_("Distort Inside"))
322         );
323         ret.push_back(ParamDesc("shade_inside")
324                 .set_local_name(_("Shade Inside"))
325         );
326         ret.push_back(ParamDesc("solid_inside")
327                 .set_local_name(_("Solid Inside"))
328         );
329         ret.push_back(ParamDesc("invert_inside")
330                 .set_local_name(_("Invert Inside"))
331         );
332         ret.push_back(ParamDesc("color_inside")
333                 .set_local_name(_("Color Inside"))
334         );
335         ret.push_back(ParamDesc("distort_outside")
336                 .set_local_name(_("Distort Outside"))
337         );
338         ret.push_back(ParamDesc("shade_outside")
339                 .set_local_name(_("Shade Outside"))
340         );
341         ret.push_back(ParamDesc("solid_outside")
342                 .set_local_name(_("Solid Outside"))
343         );
344         ret.push_back(ParamDesc("invert_outside")
345                 .set_local_name(_("Invert Outside"))
346         );
347         ret.push_back(ParamDesc("color_outside")
348                 .set_local_name(_("Color Outside"))
349         );
350
351         ret.push_back(ParamDesc("color_cycle")
352                 .set_local_name(_("Color Cycle"))
353         );
354         ret.push_back(ParamDesc("smooth_outside")
355                 .set_local_name(_("Smooth Outside"))
356                 .set_description(_("Smooth the coloration outside the set"))
357         );
358         ret.push_back(ParamDesc("broken")
359                 .set_local_name(_("Break Set"))
360                 .set_description(_("Modify equation to achieve interesting results"))
361         );
362
363
364         return ret;
365 }