1 /* === S Y N F I G ========================================================= */
2 /*! \file julia.cpp
3 ** \brief Implementation of the "Julia Set" layer
4 **
5 ** $Id$
6 **
7 ** \legal
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007 Chris Moore
10 **
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
15 **
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
20 ** \endlegal
21 **
22 ** === N O T E S ===========================================================
23 **
24 ** ========================================================================= */
25
26 /* === H E A D E R S ======================================================= */
27
28 #ifdef USING_PCH
29 # include "pch.h"
30 #else
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34
35 #include "julia.h"
36
37 #include <synfig/localization.h>
38 #include <synfig/general.h>
39
40 #include <synfig/string.h>
41 #include <synfig/time.h>
42 #include <synfig/context.h>
43 #include <synfig/paramdesc.h>
44 #include <synfig/renddesc.h>
45 #include <synfig/surface.h>
46 #include <synfig/value.h>
47 #include <synfig/valuenode.h>
48
49 #endif
50
51 using namespace std;
52 using namespace etl;
53 using namespace synfig;
54 using namespace modules;
55 using namespace lyr_std;
56
57 /* === M A C R O S ========================================================= */
58
59 #define LOG_OF_2 0.69314718055994528623
60
61 /* === G L O B A L S ======================================================= */
62
63 SYNFIG_LAYER_INIT(Julia);
64 SYNFIG_LAYER_SET_NAME(Julia,"julia");
65 SYNFIG_LAYER_SET_LOCAL_NAME(Julia,N_("Julia Set"));
66 SYNFIG_LAYER_SET_CATEGORY(Julia,N_("Fractals"));
67 SYNFIG_LAYER_SET_VERSION(Julia,"0.1");
68 SYNFIG_LAYER_SET_CVS_ID(Julia,"$Id$");
69
70 /* === P R O C E D U R E S ================================================= */
71
72 inline void
color_neg_flip(Color & color)73 color_neg_flip(Color &color)
74 {
75 if(color.get_a()==0)
76 {
77 color=Color::alpha();
78 return;
79 }
80
81 if(color.get_a()<0)
82 color=-color;
83
84 if(color.get_r()<0)
85 {
86 color.set_g(color.get_g()-color.get_r());
87 color.set_b(color.get_b()-color.get_r());
88 color.set_r(0);
89 }
90 if(color.get_g()<0)
91 {
92 color.set_r(color.get_r()-color.get_g());
93 color.set_b(color.get_b()-color.get_g());
94 color.set_g(0);
95 }
96 if(color.get_b()<0)
97 {
98 color.set_r(color.get_r()-color.get_b());
99 color.set_g(color.get_g()-color.get_b());
100 color.set_b(0);
101 }
102 }
103
104 /* === M E T H O D S ======================================================= */
105
Julia()106 Julia::Julia():
107 param_color_shift(ValueBase(Angle::deg(0)))
108 {
109 param_icolor=ValueBase(Color::black());
110 param_ocolor=ValueBase(Color::black());
111 param_iterations=ValueBase(int(32));
112 param_color_shift=ValueBase(Angle::deg(0));
113
114 param_distort_inside=ValueBase(true);
115 param_distort_outside=ValueBase(true);
116 param_shade_inside=ValueBase(true);
117 param_shade_outside=ValueBase(true);
118 param_solid_inside=ValueBase(false);
119 param_solid_outside=ValueBase(false);
120 param_invert_inside=ValueBase(false);
121 param_invert_outside=ValueBase(false);
122 param_color_inside=ValueBase(true);
123 param_color_outside=ValueBase(false);
124 param_color_cycle=ValueBase(false);
125 param_smooth_outside=ValueBase(true);
126 param_broken=ValueBase(false);
127 param_seed=ValueBase(Point(0,0));
128
129 param_bailout=ValueBase(Real(4));
130 lp=log(log(param_bailout.get(Real())));
131
132 SET_INTERPOLATION_DEFAULTS();
133 SET_STATIC_DEFAULTS();
134 }
135
136 bool
set_param(const String & param,const ValueBase & value)137 Julia::set_param(const String & param, const ValueBase &value)
138 {
139
140 IMPORT_VALUE(param_icolor);
141 IMPORT_VALUE(param_ocolor);
142 IMPORT_VALUE(param_color_shift);
143 IMPORT_VALUE(param_seed);
144
145 IMPORT_VALUE(param_distort_inside);
146 IMPORT_VALUE(param_distort_outside);
147 IMPORT_VALUE(param_shade_inside);
148 IMPORT_VALUE(param_shade_outside);
149 IMPORT_VALUE(param_solid_inside);
150 IMPORT_VALUE(param_solid_outside);
151 IMPORT_VALUE(param_invert_inside);
152 IMPORT_VALUE(param_invert_outside);
153 IMPORT_VALUE(param_color_inside);
154 IMPORT_VALUE(param_color_outside);
155
156 IMPORT_VALUE(param_color_cycle);
157 IMPORT_VALUE(param_smooth_outside);
158 IMPORT_VALUE(param_broken);
159
160 IMPORT_VALUE_PLUS(param_iterations,
161 {
162 int iterations=param_iterations.get(int());
163 iterations=value.get(iterations);
164 if(iterations<0)
165 iterations=0;
166 if(iterations>500000)
167 iterations=500000;
168 param_iterations.set(iterations);
169 return true;
170 }
171 );
172 IMPORT_VALUE_PLUS(param_bailout,
173 {
174 Real bailout=param_bailout.get(Real());
175 bailout=value.get(bailout);
176 bailout*=bailout;
177 lp=log(log(bailout));
178 param_bailout.set(bailout);
179 return true;
180 }
181 );
182
183 return false;
184 }
185
186 ValueBase
get_param(const String & param) const187 Julia::get_param(const String & param)const
188 {
189 EXPORT_VALUE(param_icolor);
190 EXPORT_VALUE(param_ocolor);
191 EXPORT_VALUE(param_color_shift);
192 EXPORT_VALUE(param_iterations);
193 EXPORT_VALUE(param_seed);
194
195 EXPORT_VALUE(param_distort_inside);
196 EXPORT_VALUE(param_distort_outside);
197 EXPORT_VALUE(param_shade_inside);
198 EXPORT_VALUE(param_shade_outside);
199 EXPORT_VALUE(param_solid_inside);
200 EXPORT_VALUE(param_solid_outside);
201 EXPORT_VALUE(param_invert_inside);
202 EXPORT_VALUE(param_invert_outside);
203 EXPORT_VALUE(param_color_inside);
204 EXPORT_VALUE(param_color_outside);
205 EXPORT_VALUE(param_color_cycle);
206 EXPORT_VALUE(param_smooth_outside);
207 EXPORT_VALUE(param_broken);
208
209 if(param=="bailout")
210 {
211 // This line is needed to copy the static and interpolation options
212 ValueBase ret(param_bailout);
213 ret.set(sqrt(param_bailout.get(Real())));
214 return ret;
215 }
216
217 EXPORT_NAME();
218 EXPORT_VERSION();
219
220 return ValueBase();
221 }
222
223 RendDesc
get_sub_renddesc_vfunc(const RendDesc & renddesc) const224 Julia::get_sub_renddesc_vfunc(const RendDesc &renddesc) const
225 {
226 RendDesc desc(renddesc);
227 desc.set_wh(512, 512);
228 desc.set_tl(Vector(-5.0, -5.0));
229 desc.set_br(Vector( 5.0, 5.0));
230 return desc;
231 }
232
233 Color
get_color(Context context,const Point & pos) const234 Julia::get_color(Context context, const Point &pos)const
235 {
236 Color icolor=param_icolor.get(Color());
237 Color ocolor=param_ocolor.get(Color());
238 Angle color_shift=param_color_shift.get(Angle());
239 int iterations=param_iterations.get(int());
240 Point seed=param_seed.get(Point());
241 bool distort_inside=param_distort_inside.get(bool());
242 bool shade_inside=param_shade_inside.get(bool());
243 bool solid_inside=param_solid_inside.get(bool());
244 bool invert_inside=param_invert_inside.get(bool());
245 bool color_inside=param_color_inside.get(bool());
246 bool distort_outside=param_distort_outside.get(bool());
247 bool shade_outside=param_shade_outside.get(bool());
248 bool solid_outside=param_solid_outside.get(bool());
249 bool invert_outside=param_invert_outside.get(bool());
250 bool color_outside=param_color_outside.get(bool());
251
252 bool color_cycle=param_color_cycle.get(bool());
253 bool smooth_outside=param_smooth_outside.get(bool());
254 bool broken=param_broken.get(bool());
255
256 Real
257 cr, ci,
258 zr, zi,
259 zr_hold;
260
261 ColorReal
262 depth, mag(0);
263
264 Color
265 ret;
266
267 cr=seed[0];
268 ci=seed[1];
269 zr=pos[0];
270 zi=pos[1];
271
272 for(int i=0;i<iterations;i++)
273 {
274 // Perform complex multiplication
275 zr_hold=zr;
276 zr=zr*zr-zi*zi + cr;
277 zi=zr_hold*zi*2 + ci;
278
279 // Use "broken" algorithm, if requested (looks weird)
280 if(broken)zr+=zi;
281
282 // Calculate Magnitude
283 mag=zr*zr+zi*zi;
284
285 if(mag>4)
286 {
287 if(smooth_outside)
288 {
289 // Darco's original mandelbrot smoothing algo
290 // depth=((Point::value_type)i+(2.0-sqrt(mag))/PI);
291
292 // Linas Vepstas algo (Better than darco's)
293 // See (http://linas.org/art-gallery/escape/smooth.html)
294 depth= (ColorReal)i - log(log(sqrt(mag))) / LOG_OF_2;
295
296 // Clamp
297 if(depth<0) depth=0;
298 }
299 else
300 depth=static_cast<ColorReal>(i);
301
302 if(solid_outside)
303 ret=ocolor;
304 else
305 if(distort_outside)
306 ret=context.get_color(Point(zr,zi));
307 else
308 ret=context.get_color(pos);
309
310 if(invert_outside)
311 ret=~ret;
312
313 if(color_outside)
314 ret=ret.set_uv(zr,zi).clamped_negative();
315
316 if(color_cycle)
317 ret=ret.rotate_uv(color_shift.operator*(depth)).clamped_negative();
318
319 if(shade_outside)
320 {
321 ColorReal alpha=depth/static_cast<ColorReal>(iterations);
322 ret=(ocolor-ret)*alpha+ret;
323 }
324 return ret;
325 }
326 }
327
328 if(solid_inside)
329 ret=icolor;
330 else
331 if(distort_inside)
332 ret=context.get_color(Point(zr,zi));
333 else
334 ret=context.get_color(pos);
335
336 if(invert_inside)
337 ret=~ret;
338
339 if(color_inside)
340 ret=ret.set_uv(zr,zi).clamped_negative();
341
342 if(shade_inside)
343 ret=(icolor-ret)*mag+ret;
344
345 return ret;
346 }
347
348 Layer::Vocab
get_param_vocab() const349 Julia::get_param_vocab()const
350 {
351 Layer::Vocab ret;
352
353 ret.push_back(ParamDesc("icolor")
354 .set_local_name(_("Inside Color"))
355 .set_description(_("Color of the Set"))
356 );
357 ret.push_back(ParamDesc("ocolor")
358 .set_local_name(_("Outside Color"))
359 .set_description(_("Color outside the Set"))
360 );
361 ret.push_back(ParamDesc("color_shift")
362 .set_local_name(_("Color Shift"))
363 );
364 ret.push_back(ParamDesc("iterations")
365 .set_local_name(_("Iterations"))
366 );
367 ret.push_back(ParamDesc("seed")
368 .set_local_name(_("Seed Point"))
369 );
370 ret.push_back(ParamDesc("bailout")
371 .set_local_name(_("Bailout ValueBase"))
372 );
373
374 ret.push_back(ParamDesc("distort_inside")
375 .set_local_name(_("Distort Inside"))
376 );
377 ret.push_back(ParamDesc("shade_inside")
378 .set_local_name(_("Shade Inside"))
379 );
380 ret.push_back(ParamDesc("solid_inside")
381 .set_local_name(_("Solid Inside"))
382 );
383 ret.push_back(ParamDesc("invert_inside")
384 .set_local_name(_("Invert Inside"))
385 );
386 ret.push_back(ParamDesc("color_inside")
387 .set_local_name(_("Color Inside"))
388 );
389 ret.push_back(ParamDesc("distort_outside")
390 .set_local_name(_("Distort Outside"))
391 );
392 ret.push_back(ParamDesc("shade_outside")
393 .set_local_name(_("Shade Outside"))
394 );
395 ret.push_back(ParamDesc("solid_outside")
396 .set_local_name(_("Solid Outside"))
397 );
398 ret.push_back(ParamDesc("invert_outside")
399 .set_local_name(_("Invert Outside"))
400 );
401 ret.push_back(ParamDesc("color_outside")
402 .set_local_name(_("Color Outside"))
403 );
404
405 ret.push_back(ParamDesc("color_cycle")
406 .set_local_name(_("Color Cycle"))
407 );
408 ret.push_back(ParamDesc("smooth_outside")
409 .set_local_name(_("Smooth Outside"))
410 .set_description(_("Smooth the coloration outside the set"))
411 );
412 ret.push_back(ParamDesc("broken")
413 .set_local_name(_("Break Set"))
414 .set_description(_("Modify equation to achieve interesting results"))
415 );
416
417
418 return ret;
419 }
420