Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-core / tags / synfig_0_61_04 / synfig-core / src / modules / lyr_std / mandelbrot.cpp
1 /*! ========================================================================
2 ** Synfig
3 ** Template File
4 ** $Id: mandelbrot.cpp,v 1.1.1.1 2005/01/04 01:23:10 darco Exp $
5 **
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 **
18 ** === N O T E S ===========================================================
19 **
20 ** ========================================================================= */
21
22 /* === H E A D E R S ======================================================= */
23
24 #ifdef USING_PCH
25 #       include "pch.h"
26 #else
27 #ifdef HAVE_CONFIG_H
28 #       include <config.h>
29 #endif
30
31 #include "mandelbrot.h"
32
33 #include <synfig/string.h>
34 #include <synfig/time.h>
35 #include <synfig/context.h>
36 #include <synfig/paramdesc.h>
37 #include <synfig/renddesc.h>
38 #include <synfig/surface.h>
39 #include <synfig/value.h>
40 #include <synfig/valuenode.h>
41
42 #endif
43
44 /* === M A C R O S ========================================================= */
45
46 #define LOG_OF_2                0.69314718055994528623
47
48 /* === G L O B A L S ======================================================= */
49
50 SYNFIG_LAYER_INIT(Mandelbrot);
51 SYNFIG_LAYER_SET_NAME(Mandelbrot,"mandelbrot");
52 SYNFIG_LAYER_SET_LOCAL_NAME(Mandelbrot,_("Mandelbrot Set"));
53 SYNFIG_LAYER_SET_CATEGORY(Mandelbrot,_("Fractals"));
54 SYNFIG_LAYER_SET_VERSION(Mandelbrot,"0.2");
55 SYNFIG_LAYER_SET_CVS_ID(Mandelbrot,"$Id: mandelbrot.cpp,v 1.1.1.1 2005/01/04 01:23:10 darco Exp $");
56
57 /* === P R O C E D U R E S ================================================= */
58
59 inline void
60 color_neg_flip(Color &color)
61 {
62         if(color.get_a()==0)
63         {
64                 color=Color::alpha();
65                 return;
66         }
67
68         if(color.get_a()<0)
69                 color=-color;
70
71         if(color.get_r()<0)
72         {
73                 color.set_g(color.get_g()-color.get_r());
74                 color.set_b(color.get_b()-color.get_r());
75                 color.set_r(0);
76         }
77         if(color.get_g()<0)
78         {
79                 color.set_r(color.get_r()-color.get_g());
80                 color.set_b(color.get_b()-color.get_g());
81                 color.set_g(0);
82         }
83         if(color.get_b()<0)
84         {
85                 color.set_r(color.get_r()-color.get_b());
86                 color.set_g(color.get_g()-color.get_b());
87                 color.set_b(0);
88         }
89 }
90
91 /* === M E T H O D S ======================================================= */
92
93 Mandelbrot::Mandelbrot():
94         gradient_offset_inside(0.0),
95         gradient_offset_outside(0.0),
96         gradient_loop_inside(true),
97         gradient_scale_outside(1.0),
98         gradient_inside(Color::alpha(),Color::black()),
99         gradient_outside(Color::alpha(),Color::black())
100 {
101         iterations=32;
102 //      color_shift=Angle::deg(0);
103
104         distort_inside=true;
105         distort_outside=true;
106         solid_inside=false;
107         solid_outside=false;
108         invert_inside=false;
109         invert_outside=false;
110         shade_inside=true;
111         shade_outside=true;
112
113         smooth_outside=true;
114         broken=false;
115         
116         bailout=4;
117         lp=log(log(bailout));
118 }
119         
120 bool
121 Mandelbrot::set_param(const String & param, const ValueBase &value)
122 {
123
124 //      IMPORT(color_shift);
125
126         IMPORT(gradient_offset_inside);
127         IMPORT(gradient_offset_outside);
128         IMPORT(gradient_loop_inside);
129         IMPORT(gradient_scale_outside);
130         
131         IMPORT(distort_inside);
132         IMPORT(distort_outside);
133         IMPORT(solid_inside);
134         IMPORT(solid_outside);
135         IMPORT(invert_inside);
136         IMPORT(invert_outside);
137         IMPORT(shade_inside);
138         IMPORT(shade_outside);
139
140         IMPORT(smooth_outside);
141         IMPORT(broken);
142
143         IMPORT(gradient_inside);
144         IMPORT(gradient_outside);
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 Mandelbrot::get_param(const String & param)const
168 {
169 //      EXPORT(icolor);
170 //      EXPORT(ocolor);
171 //      EXPORT(color_shift);
172         EXPORT(iterations);
173
174         EXPORT(gradient_offset_inside);
175         EXPORT(gradient_offset_outside);
176         EXPORT(gradient_loop_inside);
177         EXPORT(gradient_scale_outside);
178
179         EXPORT(distort_inside);
180         EXPORT(distort_outside);
181         EXPORT(solid_inside);
182         EXPORT(solid_outside);
183         EXPORT(invert_inside);
184         EXPORT(invert_outside);
185         EXPORT(shade_inside);
186         EXPORT(shade_outside);
187         EXPORT(smooth_outside);
188         EXPORT(broken);
189
190         EXPORT(gradient_inside);
191         EXPORT(gradient_outside);
192         
193         if(param=="bailout")
194                 return sqrt(bailout);
195
196         EXPORT_NAME();
197         EXPORT_VERSION();
198                 
199         return ValueBase();     
200 }
201
202 Layer::Vocab
203 Mandelbrot::get_param_vocab()const
204 {
205         Layer::Vocab ret;
206         
207         
208         ret.push_back(ParamDesc("iterations")
209                 .set_local_name(_("Iterations"))
210         );
211         ret.push_back(ParamDesc("bailout")
212                 .set_local_name(_("Bailout ValueBase"))
213         );
214
215         ret.push_back(ParamDesc("broken")
216                 .set_local_name(_("Break Set"))
217                 .set_description(_("Modify equation to achieve interesting results"))
218         );
219
220         
221         ret.push_back(ParamDesc("distort_inside")
222                 .set_local_name(_("Distort Inside"))
223                 .set_group(_("Inside"))
224         );
225         ret.push_back(ParamDesc("shade_inside")
226                 .set_local_name(_("Shade Inside"))
227                 .set_group(_("Inside"))
228         );
229         ret.push_back(ParamDesc("solid_inside")
230                 .set_local_name(_("Solid Inside"))
231                 .set_group(_("Inside"))
232         );
233         ret.push_back(ParamDesc("invert_inside")
234                 .set_local_name(_("Invert Inside"))
235                 .set_group(_("Inside"))
236         );
237         ret.push_back(ParamDesc("gradient_inside")
238                 .set_local_name(_("Gradient Inside"))
239                 .set_group(_("Inside"))
240         );
241         ret.push_back(ParamDesc("gradient_offset_inside")
242                 .set_local_name(_("Offset Inside"))
243                 .set_group(_("Inside"))
244         );
245         ret.push_back(ParamDesc("gradient_loop_inside")
246                 .set_local_name(_("Loop Inside"))
247                 .set_group(_("Inside"))
248         );
249
250         ret.push_back(ParamDesc("distort_outside")
251                 .set_local_name(_("Distort Outside"))
252                 .set_group(_("Outside"))
253         );
254         ret.push_back(ParamDesc("shade_outside")
255                 .set_local_name(_("Shade Outside"))
256                 .set_group(_("Outside"))
257         );
258         ret.push_back(ParamDesc("solid_outside")
259                 .set_local_name(_("Solid Outside"))
260                 .set_group(_("Outside"))
261         );
262         ret.push_back(ParamDesc("invert_outside")
263                 .set_local_name(_("Invert Outside"))
264                 .set_group(_("Outside"))
265         );
266         ret.push_back(ParamDesc("gradient_outside")
267                 .set_local_name(_("Gradient outside"))
268                 .set_group(_("Outside"))
269         );
270         ret.push_back(ParamDesc("smooth_outside")
271                 .set_local_name(_("Smooth Outside"))
272                 .set_description(_("Smooth the coloration outside the set"))
273                 .set_group(_("Outside"))
274         );
275         ret.push_back(ParamDesc("gradient_offset_outside")
276                 .set_local_name(_("Offset Outside"))
277                 .set_group(_("Outside"))
278         );
279         ret.push_back(ParamDesc("gradient_scale_outside")
280                 .set_local_name(_("Scale Outside"))
281                 .set_group(_("Outside"))
282         );
283                 
284         return ret;
285 }
286
287 Color
288 Mandelbrot::get_color(Context context, const Point &pos)const
289 {
290         Real
291                 cr, ci,
292                 zr, zi,
293                 zr_hold;
294         
295         ColorReal
296                 depth, mag;
297         
298         Color
299                 ret;
300
301         
302         zr=zi=0;
303         cr=pos[0];
304         ci=pos[1];
305         
306         for(int i=0;i<iterations;i++)
307         {
308                 // Perform complex multiplication
309                 zr_hold=zr;
310                 zr=zr*zr-zi*zi + cr;
311                 if(broken)zr+=zi; // Use "broken" algorithm, if requested (looks weird)
312                 zi=zr_hold*zi*2 + ci;
313
314                 
315                 // Calculate Magnitude
316                 mag=zr*zr+zi*zi;
317
318                 if(mag>bailout)
319                 {       
320                         if(smooth_outside)
321                         {
322                                 // Darco's original mandelbrot smoothing algo
323                                 // depth=((Point::value_type)i+(2.0-sqrt(mag))/PI);
324
325                                 // Linas Vepstas algo (Better than darco's)
326                                 // See (http://linas.org/art-gallery/escape/smooth.html)
327                                 depth= (ColorReal)i + LOG_OF_2*lp - log(log(sqrt(mag))) / LOG_OF_2;
328
329                                 // Clamp
330                                 if(depth<0) depth=0;
331                         }
332                         else
333                                 depth=static_cast<ColorReal>(i);
334
335                         ColorReal amount(depth/static_cast<ColorReal>(iterations));
336                         amount=amount*gradient_scale_outside+gradient_offset_outside;
337                         amount-=floor(amount);
338                         
339                         if(solid_outside)
340                                 ret=gradient_outside(amount);
341                         else
342                         {
343                                 if(distort_outside)
344                                         ret=context.get_color(Point(pos[0]+zr,pos[1]+zi));
345                                 else
346                                         ret=context.get_color(pos);
347                                 
348                                 if(invert_outside)
349                                         ret=~ret;
350
351                                 if(shade_outside)
352                                         ret=Color::blend(gradient_outside(amount), ret, 1.0);
353                         }
354
355                         
356                         return ret;
357                 }
358         }
359
360         ColorReal amount(abs(mag+gradient_offset_inside));
361         if(gradient_loop_inside)
362                 amount-=floor(amount);
363
364         if(solid_inside)
365                 ret=gradient_inside(amount);
366         else
367         {
368                 if(distort_inside)
369                         ret=context.get_color(Point(pos[0]+zr,pos[1]+zi));
370                 else
371                         ret=context.get_color(pos);
372                 
373                 if(invert_inside)
374                         ret=~ret;
375
376                 if(shade_inside)
377                         ret=Color::blend(gradient_inside(amount), ret, 1.0);
378         }
379         
380         return ret;
381 }