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