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