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 / mandelbrot.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file mandelbrot.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 "mandelbrot.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(Mandelbrot);
54 SYNFIG_LAYER_SET_NAME(Mandelbrot,"mandelbrot");
55 SYNFIG_LAYER_SET_LOCAL_NAME(Mandelbrot,_("Mandelbrot Set"));
56 SYNFIG_LAYER_SET_CATEGORY(Mandelbrot,_("Fractals"));
57 SYNFIG_LAYER_SET_VERSION(Mandelbrot,"0.2");
58 SYNFIG_LAYER_SET_CVS_ID(Mandelbrot,"$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 Mandelbrot::Mandelbrot():
97         gradient_offset_inside(0.0),
98         gradient_offset_outside(0.0),
99         gradient_loop_inside(true),
100         gradient_scale_outside(1.0),
101         gradient_inside(Color::alpha(),Color::black()),
102         gradient_outside(Color::alpha(),Color::black())
103 {
104         iterations=32;
105 //      color_shift=Angle::deg(0);
106
107         distort_inside=true;
108         distort_outside=true;
109         solid_inside=false;
110         solid_outside=false;
111         invert_inside=false;
112         invert_outside=false;
113         shade_inside=true;
114         shade_outside=true;
115
116         smooth_outside=true;
117         broken=false;
118
119         bailout=4;
120         lp=log(log(bailout));
121 }
122
123 bool
124 Mandelbrot::set_param(const String & param, const ValueBase &value)
125 {
126
127 //      IMPORT(color_shift);
128
129         IMPORT(gradient_offset_inside);
130         IMPORT(gradient_offset_outside);
131         IMPORT(gradient_loop_inside);
132         IMPORT(gradient_scale_outside);
133
134         IMPORT(distort_inside);
135         IMPORT(distort_outside);
136         IMPORT(solid_inside);
137         IMPORT(solid_outside);
138         IMPORT(invert_inside);
139         IMPORT(invert_outside);
140         IMPORT(shade_inside);
141         IMPORT(shade_outside);
142
143         IMPORT(smooth_outside);
144         IMPORT(broken);
145
146         IMPORT(gradient_inside);
147         IMPORT(gradient_outside);
148
149         if(param=="iterations" && value.same_as(iterations))
150         {
151                 iterations=value.get(iterations);
152                 if(iterations<0)
153                         iterations=0;
154                 if(iterations>500000)
155                         iterations=500000;
156                 return true;
157         }
158         if(param=="bailout" && value.same_as(bailout))
159         {
160                 bailout=value.get(bailout);
161                 bailout*=bailout;
162                 lp=log(log(bailout));
163                 return true;
164         }
165
166         return false;
167 }
168
169 ValueBase
170 Mandelbrot::get_param(const String & param)const
171 {
172 //      EXPORT(icolor);
173 //      EXPORT(ocolor);
174 //      EXPORT(color_shift);
175         EXPORT(iterations);
176
177         EXPORT(gradient_offset_inside);
178         EXPORT(gradient_offset_outside);
179         EXPORT(gradient_loop_inside);
180         EXPORT(gradient_scale_outside);
181
182         EXPORT(distort_inside);
183         EXPORT(distort_outside);
184         EXPORT(solid_inside);
185         EXPORT(solid_outside);
186         EXPORT(invert_inside);
187         EXPORT(invert_outside);
188         EXPORT(shade_inside);
189         EXPORT(shade_outside);
190         EXPORT(smooth_outside);
191         EXPORT(broken);
192
193         EXPORT(gradient_inside);
194         EXPORT(gradient_outside);
195
196         if(param=="bailout")
197                 return sqrt(bailout);
198
199         EXPORT_NAME();
200         EXPORT_VERSION();
201
202         return ValueBase();
203 }
204
205 Layer::Vocab
206 Mandelbrot::get_param_vocab()const
207 {
208         Layer::Vocab ret;
209
210
211         ret.push_back(ParamDesc("iterations")
212                 .set_local_name(_("Iterations"))
213         );
214         ret.push_back(ParamDesc("bailout")
215                 .set_local_name(_("Bailout ValueBase"))
216         );
217
218         ret.push_back(ParamDesc("broken")
219                 .set_local_name(_("Break Set"))
220                 .set_description(_("Modify equation to achieve interesting results"))
221         );
222
223
224         ret.push_back(ParamDesc("distort_inside")
225                 .set_local_name(_("Distort Inside"))
226                 .set_group(_("Inside"))
227         );
228         ret.push_back(ParamDesc("shade_inside")
229                 .set_local_name(_("Shade Inside"))
230                 .set_group(_("Inside"))
231         );
232         ret.push_back(ParamDesc("solid_inside")
233                 .set_local_name(_("Solid Inside"))
234                 .set_group(_("Inside"))
235         );
236         ret.push_back(ParamDesc("invert_inside")
237                 .set_local_name(_("Invert Inside"))
238                 .set_group(_("Inside"))
239         );
240         ret.push_back(ParamDesc("gradient_inside")
241                 .set_local_name(_("Gradient Inside"))
242                 .set_group(_("Inside"))
243         );
244         ret.push_back(ParamDesc("gradient_offset_inside")
245                 .set_local_name(_("Offset Inside"))
246                 .set_group(_("Inside"))
247         );
248         ret.push_back(ParamDesc("gradient_loop_inside")
249                 .set_local_name(_("Loop Inside"))
250                 .set_group(_("Inside"))
251         );
252
253         ret.push_back(ParamDesc("distort_outside")
254                 .set_local_name(_("Distort Outside"))
255                 .set_group(_("Outside"))
256         );
257         ret.push_back(ParamDesc("shade_outside")
258                 .set_local_name(_("Shade Outside"))
259                 .set_group(_("Outside"))
260         );
261         ret.push_back(ParamDesc("solid_outside")
262                 .set_local_name(_("Solid Outside"))
263                 .set_group(_("Outside"))
264         );
265         ret.push_back(ParamDesc("invert_outside")
266                 .set_local_name(_("Invert Outside"))
267                 .set_group(_("Outside"))
268         );
269         ret.push_back(ParamDesc("gradient_outside")
270                 .set_local_name(_("Gradient outside"))
271                 .set_group(_("Outside"))
272         );
273         ret.push_back(ParamDesc("smooth_outside")
274                 .set_local_name(_("Smooth Outside"))
275                 .set_description(_("Smooth the coloration outside the set"))
276                 .set_group(_("Outside"))
277         );
278         ret.push_back(ParamDesc("gradient_offset_outside")
279                 .set_local_name(_("Offset Outside"))
280                 .set_group(_("Outside"))
281         );
282         ret.push_back(ParamDesc("gradient_scale_outside")
283                 .set_local_name(_("Scale Outside"))
284                 .set_group(_("Outside"))
285         );
286
287         return ret;
288 }
289
290 Color
291 Mandelbrot::get_color(Context context, const Point &pos)const
292 {
293         Real
294                 cr, ci,
295                 zr, zi,
296                 zr_hold;
297
298         ColorReal
299                 depth, mag;
300
301         Color
302                 ret;
303
304
305         zr=zi=0;
306         cr=pos[0];
307         ci=pos[1];
308
309         for(int i=0;i<iterations;i++)
310         {
311                 // Perform complex multiplication
312                 zr_hold=zr;
313                 zr=zr*zr-zi*zi + cr;
314                 if(broken)zr+=zi; // Use "broken" algorithm, if requested (looks weird)
315                 zi=zr_hold*zi*2 + ci;
316
317
318                 // Calculate Magnitude
319                 mag=zr*zr+zi*zi;
320
321                 if(mag>bailout)
322                 {
323                         if(smooth_outside)
324                         {
325                                 // Darco's original mandelbrot smoothing algo
326                                 // depth=((Point::value_type)i+(2.0-sqrt(mag))/PI);
327
328                                 // Linas Vepstas algo (Better than darco's)
329                                 // See (http://linas.org/art-gallery/escape/smooth.html)
330                                 depth= (ColorReal)i + LOG_OF_2*lp - log(log(sqrt(mag))) / LOG_OF_2;
331
332                                 // Clamp
333                                 if(depth<0) depth=0;
334                         }
335                         else
336                                 depth=static_cast<ColorReal>(i);
337
338                         ColorReal amount(depth/static_cast<ColorReal>(iterations));
339                         amount=amount*gradient_scale_outside+gradient_offset_outside;
340                         amount-=floor(amount);
341
342                         if(solid_outside)
343                                 ret=gradient_outside(amount);
344                         else
345                         {
346                                 if(distort_outside)
347                                         ret=context.get_color(Point(pos[0]+zr,pos[1]+zi));
348                                 else
349                                         ret=context.get_color(pos);
350
351                                 if(invert_outside)
352                                         ret=~ret;
353
354                                 if(shade_outside)
355                                         ret=Color::blend(gradient_outside(amount), ret, 1.0);
356                         }
357
358
359                         return ret;
360                 }
361         }
362
363         ColorReal amount(abs(mag+gradient_offset_inside));
364         if(gradient_loop_inside)
365                 amount-=floor(amount);
366
367         if(solid_inside)
368                 ret=gradient_inside(amount);
369         else
370         {
371                 if(distort_inside)
372                         ret=context.get_color(Point(pos[0]+zr,pos[1]+zi));
373                 else
374                         ret=context.get_color(pos);
375
376                 if(invert_inside)
377                         ret=~ret;
378
379                 if(shade_inside)
380                         ret=Color::blend(gradient_inside(amount), ret, 1.0);
381         }
382
383         return ret;
384 }