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