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